diff --git a/DDrawCompat/D3dDdi/KernelModeThunks.cpp b/DDrawCompat/D3dDdi/KernelModeThunks.cpp index 424d916..2b78086 100644 --- a/DDrawCompat/D3dDdi/KernelModeThunks.cpp +++ b/DDrawCompat/D3dDdi/KernelModeThunks.cpp @@ -28,6 +28,7 @@ namespace D3dDdi::KernelModeThunks::AdapterInfo g_lastOpenAdapterInfo = {}; Compat::SrwLock g_adapterInfoSrwLock; std::string g_lastDDrawDeviceName; + bool g_isExclusiveFullscreen = false; decltype(&D3DKMTSubmitPresentBltToHwQueue) g_origSubmitPresentBltToHwQueue = nullptr; decltype(&D3DKMTSubmitPresentToHwQueue) g_origSubmitPresentToHwQueue = nullptr; @@ -249,13 +250,34 @@ namespace return LOG_RESULT(result); } + NTSTATUS APIENTRY releaseProcessVidPnSourceOwners(HANDLE hProcess) + { + LOG_FUNC("D3DKMTReleaseProcessVidPnSourceOwners", hProcess); + NTSTATUS result = D3DKMTReleaseProcessVidPnSourceOwners(hProcess); + if (SUCCEEDED(result)) + { + g_isExclusiveFullscreen = false; + } + return LOG_RESULT(result); + } + NTSTATUS APIENTRY setGammaRamp(const D3DKMT_SETGAMMARAMP* pData) { LOG_FUNC("D3DKMTSetGammaRamp", pData); + NTSTATUS result = 0; UINT vsyncCounter = D3dDdi::KernelModeThunks::getVsyncCounter(); DDraw::RealPrimarySurface::setUpdateReady(); DDraw::RealPrimarySurface::flush(); - HRESULT result = D3DKMTSetGammaRamp(pData); + if (g_isExclusiveFullscreen || D3DDDI_GAMMARAMP_RGB256x3x16 != pData->Type || !pData->pGammaRampRgb256x3x16) + { + D3dDdi::ShaderBlitter::resetGammaRamp(); + result = D3DKMTSetGammaRamp(pData); + } + else + { + D3dDdi::ShaderBlitter::setGammaRamp(*pData->pGammaRampRgb256x3x16); + DDraw::RealPrimarySurface::scheduleUpdate(); + } if (SUCCEEDED(result)) { D3dDdi::KernelModeThunks::waitForVsyncCounter(vsyncCounter + 1); @@ -263,6 +285,17 @@ namespace return LOG_RESULT(result); } + NTSTATUS APIENTRY setVidPnSourceOwner(const D3DKMT_SETVIDPNSOURCEOWNER* pData) + { + LOG_FUNC("D3DKMTSetVidPnSourceOwner", pData); + NTSTATUS result = D3DKMTSetVidPnSourceOwner(pData); + if (SUCCEEDED(result)) + { + g_isExclusiveFullscreen = 0 != pData->VidPnSourceCount; + } + return LOG_RESULT(result); + } + NTSTATUS APIENTRY submitPresentToHwQueue(D3DKMT_SUBMITPRESENTTOHWQUEUE* pData) { LOG_FUNC("D3DKMTSubmitPresentToHwQueue", pData); @@ -412,7 +445,9 @@ namespace D3dDdi Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTOpenAdapterFromHdc", openAdapterFromHdc); Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTPresent", present); Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTQueryAdapterInfo", queryAdapterInfo); + Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTReleaseProcessVidPnSourceOwners", releaseProcessVidPnSourceOwners); Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTSetGammaRamp", setGammaRamp); + Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTSetVidPnSourceOwner", setVidPnSourceOwner); Compat::hookIatFunction(Dll::g_origDDrawModule, "D3DKMTSubmitPresentToHwQueue", submitPresentToHwQueue); Dll::createThread(&vsyncThreadProc, nullptr, THREAD_PRIORITY_TIME_CRITICAL); diff --git a/DDrawCompat/D3dDdi/Log/CommonLog.cpp b/DDrawCompat/D3dDdi/Log/CommonLog.cpp index 1273606..b58c46f 100644 --- a/DDrawCompat/D3dDdi/Log/CommonLog.cpp +++ b/DDrawCompat/D3dDdi/Log/CommonLog.cpp @@ -10,6 +10,14 @@ std::ostream& operator<<(std::ostream& os, const D3DDDI_ALLOCATIONLIST& data) << Compat::hex(data.Value); } +std::ostream& operator<<(std::ostream& os, const D3DDDI_GAMMA_RAMP_RGB256x3x16& data) +{ + return Compat::LogStruct(os) + << Compat::array(data.Red, 256) + << Compat::array(data.Green, 256) + << Compat::array(data.Blue, 256); +} + std::ostream& operator<<(std::ostream& os, const D3DDDI_PATCHLOCATIONLIST& data) { return Compat::LogStruct(os) diff --git a/DDrawCompat/D3dDdi/Log/CommonLog.h b/DDrawCompat/D3dDdi/Log/CommonLog.h index 6a92c60..138a755 100644 --- a/DDrawCompat/D3dDdi/Log/CommonLog.h +++ b/DDrawCompat/D3dDdi/Log/CommonLog.h @@ -6,6 +6,7 @@ #include std::ostream& operator<<(std::ostream& os, const D3DDDI_ALLOCATIONLIST& data); +std::ostream& operator<<(std::ostream& os, const D3DDDI_GAMMA_RAMP_RGB256x3x16& data); std::ostream& operator<<(std::ostream& os, const D3DDDI_PATCHLOCATIONLIST& data); std::ostream& operator<<(std::ostream& os, const D3DDDI_RATIONAL& val); std::ostream& operator<<(std::ostream& os, D3DDDIFORMAT val); diff --git a/DDrawCompat/D3dDdi/Log/KernelModeThunksLog.cpp b/DDrawCompat/D3dDdi/Log/KernelModeThunksLog.cpp index 4d9f775..b0937de 100644 --- a/DDrawCompat/D3dDdi/Log/KernelModeThunksLog.cpp +++ b/DDrawCompat/D3dDdi/Log/KernelModeThunksLog.cpp @@ -135,7 +135,7 @@ std::ostream& operator<<(std::ostream& os, const D3DKMT_SETGAMMARAMP& data) << Compat::hex(data.hDevice) << data.VidPnSourceId << data.Type - << static_cast(data.pGammaRampRgb256x3x16) + << data.pGammaRampRgb256x3x16 << data.Size; } diff --git a/DDrawCompat/D3dDdi/Resource.cpp b/DDrawCompat/D3dDdi/Resource.cpp index 850bae4..dac1ec7 100644 --- a/DDrawCompat/D3dDdi/Resource.cpp +++ b/DDrawCompat/D3dDdi/Resource.cpp @@ -465,20 +465,15 @@ namespace D3dDdi return false; } - auto& repo = SurfaceRepository::get(m_device.getAdapter()); - auto newRt = &repo.getTempRenderTarget(newSrcWidth, newSrcHeight, 1); - if (newRt->resource == rt) - { - newRt = &repo.getTempRenderTarget(newSrcWidth, newSrcHeight, 0); - } - if (!newRt->resource) + auto& nextRt = getNextRenderTarget(rt, newSrcWidth, newSrcHeight); + if (!nextRt.resource) { return false; } - m_device.getShaderBlitter().textureBlt(*newRt->resource, 0, { 0, 0, newSrcWidth, newSrcHeight }, + m_device.getShaderBlitter().textureBlt(*nextRt.resource, 0, { 0, 0, newSrcWidth, newSrcHeight }, *rt, 0, { 0, 0, srcWidth, srcHeight }, D3DTEXF_LINEAR); - rt = newRt->resource; + rt = nextRt.resource; srcWidth = newSrcWidth; srcHeight = newSrcHeight; return true; @@ -531,11 +526,6 @@ namespace D3dDdi } } - void* Resource::getLockPtr(UINT subResourceIndex) - { - return m_lockData.empty() ? nullptr : m_lockData[subResourceIndex].data; - } - D3DDDIFORMAT Resource::getFormatConfig() { if (m_fixedData.Flags.RenderTarget && !m_fixedData.Flags.MatchGdiPrimary && D3DDDIPOOL_SYSTEMMEM != m_fixedData.Pool && @@ -550,6 +540,11 @@ namespace D3dDdi return m_fixedData.Format; } + void* Resource::getLockPtr(UINT subResourceIndex) + { + return m_lockData.empty() ? nullptr : m_lockData[subResourceIndex].data; + } + std::pair Resource::getMultisampleConfig() { if ((m_fixedData.Flags.RenderTarget && !m_fixedData.Flags.Texture && !m_fixedData.Flags.MatchGdiPrimary || @@ -561,6 +556,17 @@ namespace D3dDdi return { D3DDDIMULTISAMPLE_NONE, 0 }; } + const SurfaceRepository::Surface& Resource::getNextRenderTarget(Resource* currentRt, DWORD width, DWORD height) + { + auto& repo = SurfaceRepository::get(m_device.getAdapter()); + auto nextRt = &repo.getTempRenderTarget(width, height, 1); + if (nextRt->resource == currentRt) + { + nextRt = &repo.getTempRenderTarget(width, height, 0); + } + return *nextRt; + } + RECT Resource::getRect(UINT subResourceIndex) { const auto& si = m_fixedData.pSurfList[subResourceIndex]; @@ -873,23 +879,46 @@ namespace D3dDdi return S_OK; } - if (Config::Settings::DisplayFilter::BILINEAR == Config::displayFilter.get()) + const LONG dstWidth = data.DstRect.right - data.DstRect.left; + const LONG dstHeight = data.DstRect.bottom - data.DstRect.top; + while (downscale(rt, data.SrcRect.right, data.SrcRect.bottom, dstWidth, dstHeight)) { - const LONG dstWidth = data.DstRect.right - data.DstRect.left; - const LONG dstHeight = data.DstRect.bottom - data.DstRect.top; - while (downscale(rt, data.SrcRect.right, data.SrcRect.bottom, dstWidth, dstHeight)) - { - } - - m_device.getShaderBlitter().genBilinearBlt(*this, data.DstSubResourceIndex, data.DstRect, - *rt, data.SrcRect, Config::displayFilter.getParam()); - return S_OK; } - data.hSrcResource = *rt; - data.SrcSubResourceIndex = 0; - data.Flags.Point = 1; - return m_device.getOrigVtable().pfnBlt(m_device, &data); + const SurfaceRepository::Surface* rtGamma = nullptr; + if (!ShaderBlitter::isGammaRampDefault() && + SurfaceRepository::get(m_device.getAdapter()).getGammaRampTexture()) + { + rtGamma = &getNextRenderTarget(rt, dstWidth, dstHeight); + } + const bool useGamma = rtGamma && rtGamma->resource; + auto& rtNext = useGamma ? *rtGamma->resource : *this; + auto rtNextIndex = useGamma ? 0 : data.DstSubResourceIndex; + auto rtNextRect = useGamma ? RECT{ 0, 0, dstWidth, dstHeight } : data.DstRect; + + if (Config::Settings::DisplayFilter::BILINEAR == Config::displayFilter.get()) + { + m_device.getShaderBlitter().genBilinearBlt(rtNext, rtNextIndex, rtNextRect, + *rt, data.SrcRect, Config::displayFilter.getParam()); + } + else + { + D3DDDIARG_BLT blt = {}; + blt.hSrcResource = *rt; + blt.SrcSubResourceIndex = 0; + blt.SrcRect = data.SrcRect; + blt.hDstResource = rtNext; + blt.DstSubResourceIndex = rtNextIndex; + blt.DstRect = rtNextRect; + blt.Flags.Point = 1; + m_device.getOrigVtable().pfnBlt(m_device, &blt); + } + + if (useGamma) + { + m_device.getShaderBlitter().gammaBlt(*this, data.DstSubResourceIndex, data.DstRect, rtNext, rtNextRect); + } + return S_OK; } void Resource::presentLayeredWindows(Resource& dst, UINT dstSubResourceIndex, const RECT& dstRect) diff --git a/DDrawCompat/D3dDdi/Resource.h b/DDrawCompat/D3dDdi/Resource.h index a12213a..928b9be 100644 --- a/DDrawCompat/D3dDdi/Resource.h +++ b/DDrawCompat/D3dDdi/Resource.h @@ -90,6 +90,7 @@ namespace D3dDdi void fixResourceData(); D3DDDIFORMAT getFormatConfig(); std::pair getMultisampleConfig(); + const SurfaceRepository::Surface& getNextRenderTarget(Resource* currentRt, DWORD width, DWORD height); RECT getRect(UINT subResourceIndex); SIZE getScaledSize(); bool isValidRect(UINT subResourceIndex, const RECT& rect); diff --git a/DDrawCompat/D3dDdi/ShaderBlitter.cpp b/DDrawCompat/D3dDdi/ShaderBlitter.cpp index 0127314..dc0c08f 100644 --- a/DDrawCompat/D3dDdi/ShaderBlitter.cpp +++ b/DDrawCompat/D3dDdi/ShaderBlitter.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -15,11 +16,27 @@ #define CONCAT(a, b) CONCAT_(a, b) #define SCOPED_STATE(state, ...) DeviceState::Scoped##state CONCAT(scopedState, __LINE__)(m_device.getState(), __VA_ARGS__) +namespace +{ + D3DDDI_GAMMA_RAMP_RGB256x3x16 g_gammaRamp; + bool g_isGammaRampDefault = true; + bool g_isGammaRampInvalidated = false; + + void setGammaValues(BYTE* ptr, USHORT* ramp) + { + for (UINT i = 0; i < 256; ++i) + { + ptr[i] = static_cast(ramp[i] * 0xFF / 0xFFFF); + } + } +} + namespace D3dDdi { ShaderBlitter::ShaderBlitter(Device& device) : m_device(device) , m_psDrawCursor(createPixelShader(g_psDrawCursor)) + , m_psGamma(createPixelShader(g_psGamma)) , m_psGenBilinear(createPixelShader(g_psGenBilinear)) , m_psPaletteLookup(createPixelShader(g_psPaletteLookup)) , m_psTextureSampler(createPixelShader(g_psTextureSampler)) @@ -206,9 +223,49 @@ namespace D3dDdi m_device.pfnDrawPrimitive(&dp, nullptr); } + void ShaderBlitter::gammaBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, + const Resource& srcResource, const RECT& srcRect) + { + LOG_FUNC("ShaderBlitter::gammaBlt", static_cast(dstResource), dstSubResourceIndex, dstRect, + static_cast(srcResource), srcRect); + + auto gammaRampTexture(SurfaceRepository::get(m_device.getAdapter()).getGammaRampTexture()); + if (!gammaRampTexture) + { + return; + } + + if (g_isGammaRampInvalidated) + { + D3DDDIARG_LOCK lock = {}; + lock.hResource = *gammaRampTexture; + lock.Flags.Discard = 1; + m_device.getOrigVtable().pfnLock(m_device, &lock); + if (!lock.pSurfData) + { + return; + } + + auto ptr = static_cast(lock.pSurfData); + setGammaValues(ptr, g_gammaRamp.Red); + setGammaValues(ptr + lock.Pitch, g_gammaRamp.Green); + setGammaValues(ptr + 2 * lock.Pitch, g_gammaRamp.Blue); + + D3DDDIARG_UNLOCK unlock = {}; + unlock.hResource = *gammaRampTexture; + m_device.getOrigVtable().pfnUnlock(m_device, &unlock); + g_isGammaRampInvalidated = false; + } + + setTempTextureStage(1, *gammaRampTexture, D3DTEXF_POINT); + blt(dstResource, dstSubResourceIndex, dstRect, srcResource, 0, srcRect, m_psGamma.get(), D3DTEXF_POINT); + } + void ShaderBlitter::genBilinearBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, const Resource& srcResource, const RECT& srcRect, UINT blurPercent) { + LOG_FUNC("ShaderBlitter::genBilinearBlt", static_cast(dstResource), dstSubResourceIndex, dstRect, + static_cast(srcResource), srcRect, blurPercent); if (100 == blurPercent) { blt(dstResource, dstSubResourceIndex, dstRect, srcResource, 0, srcRect, @@ -233,6 +290,11 @@ namespace D3dDdi blt(dstResource, dstSubResourceIndex, dstRect, srcResource, 0, srcRect, m_psGenBilinear.get(), D3DTEXF_LINEAR); } + bool ShaderBlitter::isGammaRampDefault() + { + return g_isGammaRampDefault; + } + void ShaderBlitter::palettizedBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, const Resource& srcResource, const RECT& srcRect, RGBQUAD palette[256]) { @@ -264,6 +326,24 @@ namespace D3dDdi blt(dstResource, dstSubResourceIndex, dstRect, srcResource, 0, srcRect, m_psPaletteLookup.get(), D3DTEXF_POINT); } + void ShaderBlitter::resetGammaRamp() + { + g_isGammaRampDefault = true; + g_isGammaRampInvalidated = false; + } + + void ShaderBlitter::setGammaRamp(const D3DDDI_GAMMA_RAMP_RGB256x3x16& ramp) + { + g_gammaRamp = ramp; + g_isGammaRampDefault = true; + for (WORD i = 0; i < 256 && g_isGammaRampDefault; ++i) + { + const WORD defaultRamp = i * 0xFFFF / 0xFF; + g_isGammaRampDefault = defaultRamp == ramp.Red[i] && defaultRamp == ramp.Green[i] && defaultRamp == ramp.Blue[i]; + } + g_isGammaRampInvalidated = !g_isGammaRampDefault; + } + void ShaderBlitter::setTempTextureStage(UINT stage, HANDLE texture, UINT filter, const UINT* srcColorKey) { auto& state = m_device.getState(); diff --git a/DDrawCompat/D3dDdi/ShaderBlitter.h b/DDrawCompat/D3dDdi/ShaderBlitter.h index 971b514..1e90fd6 100644 --- a/DDrawCompat/D3dDdi/ShaderBlitter.h +++ b/DDrawCompat/D3dDdi/ShaderBlitter.h @@ -25,6 +25,8 @@ namespace D3dDdi void cursorBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, HCURSOR cursor, POINT pt); + void gammaBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, + const Resource& srcResource, const RECT& srcRect); void genBilinearBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, const Resource& srcResource, const RECT& srcRect, UINT blurPercent); void palettizedBlt(const Resource& dstResource, UINT dstSubResourceIndex, const RECT& dstRect, @@ -34,6 +36,10 @@ namespace D3dDdi UINT filter, const UINT* srcColorKey = nullptr, const BYTE* alpha = nullptr, const Gdi::Region& srcRgn = nullptr); + static bool isGammaRampDefault(); + static void resetGammaRamp(); + static void setGammaRamp(const D3DDDI_GAMMA_RAMP_RGB256x3x16& ramp); + private: struct Vertex { @@ -63,6 +69,7 @@ namespace D3dDdi Device& m_device; std::unique_ptr m_psDrawCursor; + std::unique_ptr m_psGamma; std::unique_ptr m_psGenBilinear; std::unique_ptr m_psPaletteLookup; std::unique_ptr m_psTextureSampler; diff --git a/DDrawCompat/D3dDdi/SurfaceRepository.cpp b/DDrawCompat/D3dDdi/SurfaceRepository.cpp index 03586ff..21a9280 100644 --- a/DDrawCompat/D3dDdi/SurfaceRepository.cpp +++ b/DDrawCompat/D3dDdi/SurfaceRepository.cpp @@ -169,6 +169,16 @@ namespace D3dDdi return result; } + Resource* SurfaceRepository::getGammaRampTexture() + { + DDPIXELFORMAT pf = {}; + pf.dwSize = sizeof(pf); + pf.dwFlags = DDPF_LUMINANCE; + pf.dwLuminanceBitCount = 8; + pf.dwLuminanceBitMask = 0xFF; + return getSurface(m_gammaRampTexture, 256, 3, pf, DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY).resource; + } + Resource* SurfaceRepository::getLogicalXorTexture() { return getInitializedResource(m_logicalXorTexture, 256, 256, DDraw::DirectDraw::getRgbPixelFormat(8), diff --git a/DDrawCompat/D3dDdi/SurfaceRepository.h b/DDrawCompat/D3dDdi/SurfaceRepository.h index 186c630..76085cf 100644 --- a/DDrawCompat/D3dDdi/SurfaceRepository.h +++ b/DDrawCompat/D3dDdi/SurfaceRepository.h @@ -38,6 +38,7 @@ namespace D3dDdi Cursor getCursor(HCURSOR cursor); Resource* getLogicalXorTexture(); Resource* getPaletteTexture(); + Resource* getGammaRampTexture(); Surface& getSurface(Surface& surface, DWORD width, DWORD height, const DDPIXELFORMAT& pf, DWORD caps, UINT surfaceCount = 1); const Surface& getTempRenderTarget(DWORD width, DWORD height, UINT index = 0); @@ -67,6 +68,7 @@ namespace D3dDdi Surface m_cursorMaskTexture; Surface m_cursorColorTexture; Surface m_cursorTempTexture; + Surface m_gammaRampTexture; Surface m_logicalXorTexture; Surface m_paletteTexture; std::vector m_renderTargets; diff --git a/DDrawCompat/DDraw/Log.cpp b/DDrawCompat/DDraw/Log.cpp index 0006854..9608ea6 100644 --- a/DDrawCompat/DDraw/Log.cpp +++ b/DDrawCompat/DDraw/Log.cpp @@ -25,6 +25,14 @@ std::ostream& operator<<(std::ostream& os, const DDCOLORKEY& ck) << Compat::hex(ck.dwColorSpaceHighValue); } +std::ostream& operator<<(std::ostream& os, const DDGAMMARAMP& ramp) +{ + return Compat::LogStruct(os) + << Compat::array(ramp.red, 256) + << Compat::array(ramp.green, 256) + << Compat::array(ramp.blue, 256); +} + std::ostream& operator<<(std::ostream& os, const DDSCAPS& caps) { return Compat::LogStruct(os) diff --git a/DDrawCompat/DDraw/Log.h b/DDrawCompat/DDraw/Log.h index 833d295..6ec8385 100644 --- a/DDrawCompat/DDraw/Log.h +++ b/DDrawCompat/DDraw/Log.h @@ -6,6 +6,7 @@ std::ostream& operator<<(std::ostream& os, const DDBLTFX& fx); std::ostream& operator<<(std::ostream& os, const DDCOLORKEY& ck); +std::ostream& operator<<(std::ostream& os, const DDGAMMARAMP& ramp); std::ostream& operator<<(std::ostream& os, const DDSCAPS& caps); std::ostream& operator<<(std::ostream& os, const DDSCAPS2& caps); std::ostream& operator<<(std::ostream& os, const DDPIXELFORMAT& pf); diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index 1c21963..fcb9610 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -455,6 +455,7 @@ + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index e3e87f3..0c64677 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -890,6 +890,9 @@ Shaders + + Shaders + diff --git a/DDrawCompat/Shaders/Gamma.hlsl b/DDrawCompat/Shaders/Gamma.hlsl new file mode 100644 index 0000000..6865e50 --- /dev/null +++ b/DDrawCompat/Shaders/Gamma.hlsl @@ -0,0 +1,12 @@ +sampler2D s_texture : register(s0); +sampler2D s_gammaRamp : register(s1); + +float4 main(float2 texCoord : TEXCOORD0) : COLOR0 +{ + const float4 color = tex2D(s_texture, texCoord); + return float4( + tex2D(s_gammaRamp, float2(color.r, 0.0f)).r, + tex2D(s_gammaRamp, float2(color.g, 0.5f)).r, + tex2D(s_gammaRamp, float2(color.b, 1.0f)).r, + 0); +}