diff --git a/src/d3d11/d3d11_context_imm.cpp b/src/d3d11/d3d11_context_imm.cpp index 34b87726..d06b5318 100644 --- a/src/d3d11/d3d11_context_imm.cpp +++ b/src/d3d11/d3d11_context_imm.cpp @@ -14,7 +14,7 @@ namespace dxvk { const Rc& Device) : D3D11DeviceContext(pParent, Device, DxvkCsChunkFlag::SingleUse), m_csThread(Device->createContext()), - m_videoContext(this) { + m_videoContext(this, Device) { EmitCs([ cDevice = m_device, cRelaxedBarriers = pParent->GetOptions()->relaxedBarriers diff --git a/src/d3d11/d3d11_context_imm.h b/src/d3d11/d3d11_context_imm.h index 2320a660..e23fe2b4 100644 --- a/src/d3d11/d3d11_context_imm.h +++ b/src/d3d11/d3d11_context_imm.h @@ -15,6 +15,7 @@ namespace dxvk { class D3D11ImmediateContext : public D3D11DeviceContext { friend class D3D11SwapChain; + friend class D3D11VideoContext; public: D3D11ImmediateContext( diff --git a/src/d3d11/d3d11_video.cpp b/src/d3d11/d3d11_video.cpp index 0a944eab..ea3d76e3 100644 --- a/src/d3d11/d3d11_video.cpp +++ b/src/d3d11/d3d11_video.cpp @@ -4,6 +4,9 @@ #include "d3d11_context_imm.h" #include "d3d11_video.h" +#include +#include + namespace dxvk { D3D11VideoProcessorEnumerator::D3D11VideoProcessorEnumerator( @@ -302,9 +305,55 @@ namespace dxvk { D3D11VideoContext::D3D11VideoContext( - D3D11ImmediateContext* pContext) + D3D11ImmediateContext* pContext, + const Rc& Device) : m_ctx(pContext) { + const SpirvCodeBuffer vsCode(d3d11_video_blit_vert); + const SpirvCodeBuffer fsCode(d3d11_video_blit_frag); + const std::array fsResourceSlots = {{ + { 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC }, + { 1, VK_DESCRIPTOR_TYPE_SAMPLER }, + { 2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_IMAGE_VIEW_TYPE_2D }, + { 3, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_IMAGE_VIEW_TYPE_2D }, + }}; + + m_vs = Device->createShader( + VK_SHADER_STAGE_VERTEX_BIT, + 0, nullptr, { 0u, 1u }, + vsCode); + + m_fs = Device->createShader( + VK_SHADER_STAGE_FRAGMENT_BIT, + fsResourceSlots.size(), + fsResourceSlots.data(), + { 1u, 1u, 0u, 0u }, + fsCode); + + DxvkSamplerCreateInfo samplerInfo; + samplerInfo.magFilter = VK_FILTER_LINEAR; + samplerInfo.minFilter = VK_FILTER_LINEAR; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + samplerInfo.mipmapLodBias = 0.0f; + samplerInfo.mipmapLodMin = 0.0f; + samplerInfo.mipmapLodMax = 0.0f; + samplerInfo.useAnisotropy = VK_FALSE; + samplerInfo.maxAnisotropy = 1.0f; + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.compareToDepth = VK_FALSE; + samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; + samplerInfo.borderColor = VkClearColorValue(); + samplerInfo.usePixelCoord = VK_FALSE; + m_sampler = Device->createSampler(samplerInfo); + + DxvkBufferCreateInfo bufferInfo; + bufferInfo.size = sizeof(UboData); + bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + bufferInfo.stages = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + bufferInfo.access = VK_ACCESS_UNIFORM_READ_BIT; + m_ubo = Device->createBuffer(bufferInfo, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); } @@ -414,7 +463,16 @@ namespace dxvk { ID3D11VideoProcessor* pVideoProcessor, BOOL Enable, const RECT* pRect) { - Logger::err("D3D11VideoContext::VideoProcessorSetOutputTargetRect: Stub"); + auto state = static_cast(pVideoProcessor)->GetState(); + state->outputTargetRectEnabled = Enable; + + if (Enable) + state->outputTargetRect = *pRect; + + static bool errorShown = false; + + if (!std::exchange(errorShown, true)) + Logger::err("D3D11VideoContext::VideoProcessorSetOutputTargetRect: Stub."); } @@ -422,14 +480,22 @@ namespace dxvk { ID3D11VideoProcessor* pVideoProcessor, BOOL YCbCr, const D3D11_VIDEO_COLOR* pColor) { - Logger::err("D3D11VideoContext::VideoProcessorSetOutputBackgroundColor: Stub"); + auto state = static_cast(pVideoProcessor)->GetState(); + state->outputBackgroundColorIsYCbCr = YCbCr; + state->outputBackgroundColor = *pColor; + + static bool errorShown = false; + + if (!std::exchange(errorShown, true)) + Logger::err("D3D11VideoContext::VideoProcessorSetOutputBackgroundColor: Stub"); } void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetOutputColorSpace( ID3D11VideoProcessor* pVideoProcessor, const D3D11_VIDEO_PROCESSOR_COLOR_SPACE *pColorSpace) { - Logger::err("D3D11VideoContext::VideoProcessorSetOutputColorSpace: Stub"); + auto state = static_cast(pVideoProcessor)->GetState(); + state->outputColorSpace = *pColorSpace; } @@ -452,7 +518,11 @@ namespace dxvk { void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorSetOutputStereoMode( ID3D11VideoProcessor* pVideoProcessor, BOOL Enable) { - Logger::err("D3D11VideoContext::VideoProcessorSetOutputStereoMode: Stub"); + auto state = static_cast(pVideoProcessor)->GetState(); + state->outputStereoModeEnabled = Enable; + + if (Enable) + Logger::err("D3D11VideoContext: Stereo output not supported"); } @@ -470,7 +540,15 @@ namespace dxvk { ID3D11VideoProcessor* pVideoProcessor, UINT StreamIndex, D3D11_VIDEO_FRAME_FORMAT Format) { - Logger::err("D3D11VideoContext::VideoProcessorSetStreamFrameFormat: Stub"); + auto state = static_cast(pVideoProcessor)->GetStreamState(StreamIndex); + + if (!state) + return; + + state->frameFormat = Format; + + if (Format != D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE) + Logger::err(str::format("D3D11VideoContext: Unsupported frame format: ", Format)); } @@ -478,7 +556,12 @@ namespace dxvk { ID3D11VideoProcessor* pVideoProcessor, UINT StreamIndex, const D3D11_VIDEO_PROCESSOR_COLOR_SPACE *pColorSpace) { - Logger::err("D3D11VideoContext::VideoProcessorSetStreamColorSpace: Stub"); + auto state = static_cast(pVideoProcessor)->GetStreamState(StreamIndex); + + if (!state) + return; + + state->colorSpace = *pColorSpace; } @@ -497,7 +580,20 @@ namespace dxvk { UINT StreamIndex, BOOL Enable, const RECT* pRect) { - Logger::err("D3D11VideoContext::VideoProcessorSetStreamSourceRect: Stub"); + auto state = static_cast(pVideoProcessor)->GetStreamState(StreamIndex); + + if (!state) + return; + + state->srcRectEnabled = Enable; + + if (Enable) + state->srcRect = *pRect; + + static bool errorShown = false; + + if (!std::exchange(errorShown, true)) + Logger::err("D3D11VideoContext::VideoProcessorSetStreamSourceRect: Stub."); } @@ -506,7 +602,15 @@ namespace dxvk { UINT StreamIndex, BOOL Enable, const RECT* pRect) { - Logger::err("D3D11VideoContext::VideoProcessorSetStreamDestRect: Stub"); + auto state = static_cast(pVideoProcessor)->GetStreamState(StreamIndex); + + if (!state) + return; + + state->dstRectEnabled = Enable; + + if (Enable) + state->dstRect = *pRect; } @@ -565,7 +669,12 @@ namespace dxvk { ID3D11VideoProcessor* pVideoProcessor, UINT StreamIndex, BOOL Enable) { - Logger::err("D3D11VideoContext::VideoProcessorSetStreamAutoProcessingMode: Stub"); + auto state = static_cast(pVideoProcessor)->GetStreamState(StreamIndex); + + if (!state) + return; + + state->autoProcessingEnabled = Enable; } @@ -595,7 +704,16 @@ namespace dxvk { UINT StreamIndex, BOOL Enable, D3D11_VIDEO_PROCESSOR_ROTATION Rotation) { - Logger::err("D3D11VideoContext::VideoProcessorSetStreamRotation: Stub"); + auto state = static_cast(pVideoProcessor)->GetStreamState(StreamIndex); + + if (!state) + return; + + state->rotationEnabled = Enable; + state->rotation = Rotation; + + if (Enable && Rotation != D3D11_VIDEO_PROCESSOR_ROTATION_IDENTITY) + Logger::err(str::format("D3D11VideoContext: Unsupported rotation: ", Rotation)); } @@ -603,7 +721,13 @@ namespace dxvk { ID3D11VideoProcessor* pVideoProcessor, BOOL* pEnabled, RECT* pRect) { - Logger::err("D3D11VideoContext::VideoProcessorGetOutputTargetRect: Stub"); + auto state = static_cast(pVideoProcessor)->GetState(); + + if (pEnabled) + *pEnabled = state->outputTargetRectEnabled; + + if (pRect) + *pRect = state->outputTargetRect; } @@ -611,14 +735,23 @@ namespace dxvk { ID3D11VideoProcessor* pVideoProcessor, BOOL* pYCbCr, D3D11_VIDEO_COLOR* pColor) { - Logger::err("D3D11VideoContext::VideoProcessorGetOutputBackgroundColor: Stub"); + auto state = static_cast(pVideoProcessor)->GetState(); + + if (pYCbCr) + *pYCbCr = state->outputBackgroundColorIsYCbCr; + + if (pColor) + *pColor = state->outputBackgroundColor; } void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetOutputColorSpace( ID3D11VideoProcessor* pVideoProcessor, D3D11_VIDEO_PROCESSOR_COLOR_SPACE* pColorSpace) { - Logger::err("D3D11VideoContext::VideoProcessorGetOutputColorSpace: Stub"); + auto state = static_cast(pVideoProcessor)->GetState(); + + if (pColorSpace) + *pColorSpace = state->outputColorSpace; } @@ -641,7 +774,10 @@ namespace dxvk { void STDMETHODCALLTYPE D3D11VideoContext::VideoProcessorGetOutputStereoMode( ID3D11VideoProcessor* pVideoProcessor, BOOL* pEnabled) { - Logger::err("D3D11VideoContext::VideoProcessorGetOutputStereoMode: Stub"); + auto state = static_cast(pVideoProcessor)->GetState(); + + if (pEnabled) + *pEnabled = state->outputStereoModeEnabled; } @@ -659,7 +795,13 @@ namespace dxvk { ID3D11VideoProcessor* pVideoProcessor, UINT StreamIndex, D3D11_VIDEO_FRAME_FORMAT* pFormat) { - Logger::err("D3D11VideoContext::VideoProcessorGetStreamFrameFormat: Stub"); + auto state = static_cast(pVideoProcessor)->GetStreamState(StreamIndex); + + if (!state) + return; + + if (pFormat) + *pFormat = state->frameFormat; } @@ -667,7 +809,13 @@ namespace dxvk { ID3D11VideoProcessor* pVideoProcessor, UINT StreamIndex, D3D11_VIDEO_PROCESSOR_COLOR_SPACE* pColorSpace) { - Logger::err("D3D11VideoContext::VideoProcessorGetStreamColorSpace: Stub"); + auto state = static_cast(pVideoProcessor)->GetStreamState(StreamIndex); + + if (!state) + return; + + if (pColorSpace) + *pColorSpace = state->colorSpace; } @@ -686,7 +834,16 @@ namespace dxvk { UINT StreamIndex, BOOL* pEnabled, RECT* pRect) { - Logger::err("D3D11VideoContext::VideoProcessorGetStreamSourceRect: Stub"); + auto state = static_cast(pVideoProcessor)->GetStreamState(StreamIndex); + + if (!state) + return; + + if (pEnabled) + *pEnabled = state->srcRectEnabled; + + if (pRect) + *pRect = state->srcRect; } @@ -695,7 +852,16 @@ namespace dxvk { UINT StreamIndex, BOOL* pEnabled, RECT* pRect) { - Logger::err("D3D11VideoContext::VideoProcessorGetStreamDestRect: Stub"); + auto state = static_cast(pVideoProcessor)->GetStreamState(StreamIndex); + + if (!state) + return; + + if (pEnabled) + *pEnabled = state->dstRectEnabled; + + if (pRect) + *pRect = state->dstRect; } @@ -754,7 +920,12 @@ namespace dxvk { ID3D11VideoProcessor* pVideoProcessor, UINT StreamIndex, BOOL* pEnabled) { - Logger::err("D3D11VideoContext::VideoProcessorGetStreamAutoProcessingMode: Stub"); + auto state = static_cast(pVideoProcessor)->GetStreamState(StreamIndex); + + if (!state) + return; + + *pEnabled = state->autoProcessingEnabled; } @@ -784,7 +955,16 @@ namespace dxvk { UINT StreamIndex, BOOL* pEnable, D3D11_VIDEO_PROCESSOR_ROTATION* pRotation) { - Logger::err("D3D11VideoContext::VideoProcessorGetStreamRotation: Stub"); + auto state = static_cast(pVideoProcessor)->GetStreamState(StreamIndex); + + if (!state) + return; + + if (pEnable) + *pEnable = state->rotationEnabled; + + if (pRotation) + *pRotation = state->rotation; } @@ -794,8 +974,30 @@ namespace dxvk { UINT FrameIdx, UINT StreamCount, const D3D11_VIDEO_PROCESSOR_STREAM* pStreams) { - Logger::err("D3D11VideoContext::VideoProcessorBlt: Stub"); - return E_NOTIMPL; + auto videoProcessor = static_cast(pVideoProcessor); + bool hasStreamsEnabled = false; + + // Resetting and restoring all context state incurs + // a lot of overhead, so only do it as necessary + for (uint32_t i = 0; i < StreamCount; i++) { + auto streamState = videoProcessor->GetStreamState(i); + + if (!pStreams[i].Enable || !streamState) + continue; + + if (!hasStreamsEnabled) { + m_ctx->ResetState(); + BindOutputView(pOutputView); + hasStreamsEnabled = true; + } + + BlitStream(streamState, &pStreams[i]); + } + + if (hasStreamsEnabled) + m_ctx->RestoreState(); + + return S_OK; } @@ -883,4 +1085,140 @@ namespace dxvk { return E_NOTIMPL; } + + void D3D11VideoContext::ApplyColorMatrix(float pDst[3][4], const float pSrc[3][4]) { + float result[3][4]; + + for (uint32_t i = 0; i < 3; i++) { + for (uint32_t j = 0; j < 4; j++) { + result[i][j] = pSrc[i][0] * pDst[0][j] + + pSrc[i][1] * pDst[1][j] + + pSrc[i][2] * pDst[2][j] + + pSrc[i][3] * float(j == 3); + } + } + + memcpy(pDst, &result[0][0], sizeof(result)); + } + + + void D3D11VideoContext::ApplyYCbCrMatrix(float pColorMatrix[3][4], bool UseBt709) { + static const float pretransform[3][4] = { + { 0.0f, 1.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 1.0f, -0.5f }, + { 1.0f, 0.0f, 0.0f, -0.5f }, + }; + + static const float bt601[3][4] = { + { 1.0f, 0.000000f, 1.402000f, 0.0f }, + { 1.0f, -0.344136f, -0.714136f, 0.0f }, + { 1.0f, 1.772000f, 0.000000f, 0.0f }, + }; + + static const float bt709[3][4] = { + { 1.0f, 0.000000f, 1.574800f, 0.0f }, + { 1.0f, -0.187324f, -0.468124f, 0.0f }, + { 1.0f, 1.855600f, 0.000000f, 0.0f }, + }; + + ApplyColorMatrix(pColorMatrix, pretransform); + ApplyColorMatrix(pColorMatrix, UseBt709 ? bt709 : bt601); + } + + + void D3D11VideoContext::BindOutputView( + ID3D11VideoProcessorOutputView* pOutputView) { + auto dxvkView = static_cast(pOutputView)->GetView(); + + m_ctx->EmitCs([this, cView = dxvkView] (DxvkContext* ctx) { + DxvkRenderTargets rt; + rt.color[0].view = cView; + rt.color[0].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + ctx->bindRenderTargets(rt); + ctx->bindShader(VK_SHADER_STAGE_VERTEX_BIT, m_vs); + ctx->bindShader(VK_SHADER_STAGE_FRAGMENT_BIT, m_fs); + ctx->bindResourceBuffer(0, DxvkBufferSlice(m_ubo)); + + DxvkInputAssemblyState iaState; + iaState.primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + iaState.primitiveRestart = VK_FALSE; + iaState.patchVertexCount = 0; + ctx->setInputAssemblyState(iaState); + }); + + VkExtent3D viewExtent = dxvkView->mipLevelExtent(0); + m_dstExtent = { viewExtent.width, viewExtent.height }; + } + + + void D3D11VideoContext::BlitStream( + const D3D11VideoProcessorStreamState* pStreamState, + const D3D11_VIDEO_PROCESSOR_STREAM* pStream) { + if (pStream->PastFrames || pStream->FutureFrames) + Logger::err("D3D11VideoContext: Ignoring non-zero PastFrames and FutureFrames"); + + if (pStream->OutputIndex) + Logger::err("D3D11VideoContext: Ignoring non-zero OutputIndex"); + + if (pStream->InputFrameOrField) + Logger::err("D3D11VideoContext: Ignoring non-zero InputFrameOrField"); + + auto view = static_cast(pStream->pInputSurface); + + m_ctx->EmitCs([this, + cStreamState = *pStreamState, + cViews = view->GetViews(), + cIsYCbCr = view->IsYCbCr() + ] (DxvkContext* ctx) { + VkViewport viewport; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = float(m_dstExtent.width); + viewport.height = float(m_dstExtent.height); + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + VkRect2D scissor; + scissor.offset = { 0, 0 }; + scissor.extent = m_dstExtent; + + if (cStreamState.dstRectEnabled) { + viewport.x = float(cStreamState.dstRect.left); + viewport.y = float(cStreamState.dstRect.top); + viewport.width = float(cStreamState.dstRect.right) - viewport.x; + viewport.height = float(cStreamState.dstRect.bottom) - viewport.y; + } + + UboData uboData = { }; + uboData.colorMatrix[0][0] = 1.0f; + uboData.colorMatrix[1][1] = 1.0f; + uboData.colorMatrix[2][2] = 1.0f; + uboData.coordMatrix[0][0] = 1.0f; + uboData.coordMatrix[1][1] = 1.0f; + uboData.yMin = 0.0f; + uboData.yMax = 1.0f; + + if (cIsYCbCr) + ApplyYCbCrMatrix(uboData.colorMatrix, cStreamState.colorSpace.YCbCr_Matrix); + + if (cStreamState.colorSpace.Nominal_Range) { + uboData.yMin = 0.0627451f; + uboData.yMax = 0.9215686f; + } + + DxvkBufferSliceHandle uboSlice = m_ubo->allocSlice(); + memcpy(uboSlice.mapPtr, &uboData, sizeof(uboData)); + + ctx->invalidateBuffer(m_ubo, uboSlice); + ctx->setViewports(1, &viewport, &scissor); + ctx->bindResourceSampler(1, m_sampler); + + for (uint32_t i = 0; i < cViews.size(); i++) + ctx->bindResourceView(2 + i, cViews[i], nullptr); + + ctx->draw(3, 1, 0, 0); + }); + } + } diff --git a/src/d3d11/d3d11_video.h b/src/d3d11/d3d11_video.h index 60c01b68..510b8b45 100644 --- a/src/d3d11/d3d11_video.h +++ b/src/d3d11/d3d11_video.h @@ -4,6 +4,8 @@ namespace dxvk { + static constexpr uint32_t D3D11_VK_VIDEO_STREAM_COUNT = 8; + class D3D11VideoProcessorEnumerator : public D3D11DeviceChild { public: @@ -48,6 +50,26 @@ namespace dxvk { }; + struct D3D11VideoProcessorStreamState { + BOOL autoProcessingEnabled = TRUE; + BOOL dstRectEnabled = FALSE; + BOOL srcRectEnabled = FALSE; + BOOL rotationEnabled = FALSE; + RECT dstRect = RECT(); + RECT srcRect = RECT(); + D3D11_VIDEO_FRAME_FORMAT frameFormat = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE; + D3D11_VIDEO_PROCESSOR_ROTATION rotation = D3D11_VIDEO_PROCESSOR_ROTATION_IDENTITY; + D3D11_VIDEO_PROCESSOR_COLOR_SPACE colorSpace = D3D11_VIDEO_PROCESSOR_COLOR_SPACE(); + }; + + struct D3D11VideoProcessorState { + BOOL outputStereoModeEnabled = FALSE; + BOOL outputBackgroundColorIsYCbCr = FALSE; + BOOL outputTargetRectEnabled = FALSE; + RECT outputTargetRect = RECT(); + D3D11_VIDEO_COLOR outputBackgroundColor = D3D11_VIDEO_COLOR(); + D3D11_VIDEO_PROCESSOR_COLOR_SPACE outputColorSpace = D3D11_VIDEO_PROCESSOR_COLOR_SPACE(); + }; class D3D11VideoProcessor : public D3D11DeviceChild { @@ -70,10 +92,22 @@ namespace dxvk { void STDMETHODCALLTYPE GetRateConversionCaps( D3D11_VIDEO_PROCESSOR_RATE_CONVERSION_CAPS *pCaps); + D3D11VideoProcessorState* GetState() { + return &m_state; + } + + D3D11VideoProcessorStreamState* GetStreamState(UINT StreamIndex) { + return StreamIndex < D3D11_VK_VIDEO_STREAM_COUNT + ? &m_streams[StreamIndex] + : nullptr; + } + private: D3D11VideoProcessorEnumerator* m_enumerator; uint32_t m_rateConversionIndex; + D3D11VideoProcessorState m_state; + D3D11VideoProcessorStreamState m_streams[D3D11_VK_VIDEO_STREAM_COUNT]; }; @@ -104,6 +138,10 @@ namespace dxvk { return m_isYCbCr; } + std::array, 2> GetViews() const { + return m_views; + } + private: Com m_resource; @@ -138,6 +176,10 @@ namespace dxvk { void STDMETHODCALLTYPE GetDesc( D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC* pDesc); + Rc GetView() const { + return m_view; + } + private: Com m_resource; @@ -153,7 +195,8 @@ namespace dxvk { public: D3D11VideoContext( - D3D11ImmediateContext* pContext); + D3D11ImmediateContext* pContext, + const Rc& Device); ~D3D11VideoContext(); @@ -520,7 +563,31 @@ namespace dxvk { private: - D3D11ImmediateContext* m_ctx; + struct alignas(16) UboData { + float colorMatrix[3][4]; + float coordMatrix[3][2]; + float yMin, yMax; + }; + + D3D11ImmediateContext* m_ctx; + + Rc m_sampler; + Rc m_vs; + Rc m_fs; + Rc m_ubo; + + VkExtent2D m_dstExtent = { 0u, 0u }; + + void ApplyColorMatrix(float pDst[3][4], const float pSrc[3][4]); + + void ApplyYCbCrMatrix(float pColorMatrix[3][4], bool UseBt709); + + void BindOutputView( + ID3D11VideoProcessorOutputView* pOutputView); + + void BlitStream( + const D3D11VideoProcessorStreamState* pStreamState, + const D3D11_VIDEO_PROCESSOR_STREAM* pStream); }; diff --git a/src/d3d11/meson.build b/src/d3d11/meson.build index ffd1f206..995755aa 100644 --- a/src/d3d11/meson.build +++ b/src/d3d11/meson.build @@ -59,7 +59,13 @@ d3d11_src = [ 'd3d11_view_uav.cpp', ] -d3d11_dll = shared_library('d3d11'+dll_ext, dxgi_common_src + d3d11_src + d3d10_src, d3d11_res, +d3d11_shaders = files([ + 'shaders/d3d11_video_blit_frag.frag', + 'shaders/d3d11_video_blit_vert.vert', +]) + +d3d11_dll = shared_library('d3d11'+dll_ext, dxgi_common_src + d3d11_src + d3d10_src, + glsl_generator.process(d3d11_shaders), d3d11_res, name_prefix : '', dependencies : [ lib_dxgi, dxbc_dep, dxvk_dep ], include_directories : dxvk_include_path, diff --git a/src/d3d11/shaders/d3d11_video_blit_frag.frag b/src/d3d11/shaders/d3d11_video_blit_frag.frag new file mode 100644 index 00000000..d659176c --- /dev/null +++ b/src/d3d11/shaders/d3d11_video_blit_frag.frag @@ -0,0 +1,56 @@ +#version 450 + +layout(constant_id = 3) const bool c_planar = true; + +// Can't use matrix types here since even a two-row +// matrix will be padded to 16 bytes per column for +// absolutely no reason +layout(std140, set = 0, binding = 0) +uniform ubo_t { + vec4 color_matrix_r1; + vec4 color_matrix_r2; + vec4 color_matrix_r3; + vec2 coord_matrix_c1; + vec2 coord_matrix_c2; + vec2 coord_matrix_c3; + float y_min; + float y_max; +}; + +layout(location = 0) in vec2 i_texcoord; +layout(location = 0) out vec4 o_color; + +layout(set = 0, binding = 1) uniform sampler s_sampler; +layout(set = 0, binding = 2) uniform texture2D s_inputY; +layout(set = 0, binding = 3) uniform texture2D s_inputCbCr; + +void main() { + // Transform input texture coordinates to + // account for rotation and source rectangle + mat3x2 coord_matrix = mat3x2( + coord_matrix_c1, + coord_matrix_c2, + coord_matrix_c3); + + vec2 coord = coord_matrix * vec3(i_texcoord, 1.0f); + + // Fetch source image color + vec4 color = vec4(0.0f, 0.0f, 0.0f, 1.0f); + + if (c_planar) { + color.g = texture(sampler2D(s_inputY, s_sampler), coord).r; + color.rb = texture(sampler2D(s_inputCbCr, s_sampler), coord).gr; + color.g = clamp((color.g - y_min) / (y_max - y_min), 0.0f, 1.0f); + } else { + color = texture(sampler2D(s_inputY, s_sampler), coord); + } + + // Color space transformation + mat3x4 color_matrix = mat3x4( + color_matrix_r1, + color_matrix_r2, + color_matrix_r3); + + o_color.rgb = vec4(color.rgb, 1.0f) * color_matrix; + o_color.a = color.a; +} diff --git a/src/d3d11/shaders/d3d11_video_blit_vert.vert b/src/d3d11/shaders/d3d11_video_blit_vert.vert new file mode 100644 index 00000000..1980b3c9 --- /dev/null +++ b/src/d3d11/shaders/d3d11_video_blit_vert.vert @@ -0,0 +1,12 @@ +#version 450 + +layout(location = 0) out vec2 o_texcoord; + +void main() { + vec2 coord = vec2( + float(gl_VertexIndex & 1) * 2.0f, + float(gl_VertexIndex & 2)); + + o_texcoord = coord; + gl_Position = vec4(-1.0f + 2.0f * coord, 0.0f, 1.0f); +}