| // |
| // Copyright 2013 The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| |
| // PixelTransfer11.cpp: |
| // Implementation for buffer-to-texture and texture-to-buffer copies. |
| // Used to implement pixel transfers from unpack and to pack buffers. |
| // |
| |
| #include "libANGLE/renderer/d3d/d3d11/PixelTransfer11.h" |
| |
| #include "libANGLE/Buffer.h" |
| #include "libANGLE/Context.h" |
| #include "libANGLE/Texture.h" |
| #include "libANGLE/formatutils.h" |
| #include "libANGLE/renderer/d3d/d3d11/Buffer11.h" |
| #include "libANGLE/renderer/d3d/d3d11/Context11.h" |
| #include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" |
| #include "libANGLE/renderer/d3d/d3d11/Renderer11.h" |
| #include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h" |
| #include "libANGLE/renderer/d3d/d3d11/formatutils11.h" |
| #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" |
| #include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" |
| |
| // Precompiled shaders |
| #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_gs.h" |
| #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_ps_4f.h" |
| #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_ps_4i.h" |
| #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_ps_4ui.h" |
| #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_vs.h" |
| |
| namespace rx |
| { |
| |
| PixelTransfer11::PixelTransfer11(Renderer11 *renderer) |
| : mRenderer(renderer), |
| mResourcesLoaded(false), |
| mBufferToTextureVS(), |
| mBufferToTextureGS(), |
| mParamsConstantBuffer(), |
| mCopyRasterizerState(), |
| mCopyDepthStencilState() |
| {} |
| |
| PixelTransfer11::~PixelTransfer11() {} |
| |
| angle::Result PixelTransfer11::loadResources(const gl::Context *context) |
| { |
| if (mResourcesLoaded) |
| { |
| return angle::Result::Continue; |
| } |
| |
| D3D11_RASTERIZER_DESC rasterDesc; |
| rasterDesc.FillMode = D3D11_FILL_SOLID; |
| rasterDesc.CullMode = D3D11_CULL_NONE; |
| rasterDesc.FrontCounterClockwise = FALSE; |
| rasterDesc.DepthBias = 0; |
| rasterDesc.SlopeScaledDepthBias = 0.0f; |
| rasterDesc.DepthBiasClamp = 0.0f; |
| rasterDesc.DepthClipEnable = TRUE; |
| rasterDesc.ScissorEnable = FALSE; |
| rasterDesc.MultisampleEnable = FALSE; |
| rasterDesc.AntialiasedLineEnable = FALSE; |
| |
| Context11 *context11 = GetImplAs<Context11>(context); |
| |
| ANGLE_TRY(mRenderer->allocateResource(context11, rasterDesc, &mCopyRasterizerState)); |
| |
| D3D11_DEPTH_STENCIL_DESC depthStencilDesc; |
| depthStencilDesc.DepthEnable = true; |
| depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; |
| depthStencilDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; |
| depthStencilDesc.StencilEnable = FALSE; |
| depthStencilDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; |
| depthStencilDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; |
| depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; |
| depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; |
| depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; |
| depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; |
| depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; |
| depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; |
| depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; |
| depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; |
| |
| ANGLE_TRY(mRenderer->allocateResource(context11, depthStencilDesc, &mCopyDepthStencilState)); |
| |
| D3D11_BUFFER_DESC constantBufferDesc = {}; |
| constantBufferDesc.ByteWidth = roundUp<UINT>(sizeof(CopyShaderParams), 32u); |
| constantBufferDesc.Usage = D3D11_USAGE_DYNAMIC; |
| constantBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; |
| constantBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; |
| constantBufferDesc.MiscFlags = 0; |
| constantBufferDesc.StructureByteStride = 0; |
| |
| ANGLE_TRY(mRenderer->allocateResource(context11, constantBufferDesc, &mParamsConstantBuffer)); |
| mParamsConstantBuffer.setDebugName("PixelTransfer11 constant buffer"); |
| |
| // init shaders |
| ANGLE_TRY(mRenderer->allocateResource(context11, ShaderData(g_VS_BufferToTexture), |
| &mBufferToTextureVS)); |
| mBufferToTextureVS.setDebugName("BufferToTexture VS"); |
| |
| ANGLE_TRY(mRenderer->allocateResource(context11, ShaderData(g_GS_BufferToTexture), |
| &mBufferToTextureGS)); |
| mBufferToTextureGS.setDebugName("BufferToTexture GS"); |
| |
| ANGLE_TRY(buildShaderMap(context)); |
| |
| StructZero(&mParamsData); |
| |
| mResourcesLoaded = true; |
| |
| return angle::Result::Continue; |
| } |
| |
| void PixelTransfer11::setBufferToTextureCopyParams(const gl::Box &destArea, |
| const gl::Extents &destSize, |
| GLenum internalFormat, |
| const gl::PixelUnpackState &unpack, |
| unsigned int offset, |
| CopyShaderParams *parametersOut) |
| { |
| StructZero(parametersOut); |
| |
| float texelCenterX = 0.5f / static_cast<float>(destSize.width); |
| float texelCenterY = 0.5f / static_cast<float>(destSize.height); |
| |
| unsigned int bytesPerPixel = gl::GetSizedInternalFormatInfo(internalFormat).pixelBytes; |
| unsigned int alignmentBytes = static_cast<unsigned int>(unpack.alignment); |
| unsigned int alignmentPixels = |
| (alignmentBytes <= bytesPerPixel ? 1 : alignmentBytes / bytesPerPixel); |
| |
| parametersOut->FirstPixelOffset = offset / bytesPerPixel; |
| parametersOut->PixelsPerRow = |
| static_cast<unsigned int>((unpack.rowLength > 0) ? unpack.rowLength : destArea.width); |
| parametersOut->RowStride = roundUp(parametersOut->PixelsPerRow, alignmentPixels); |
| parametersOut->RowsPerSlice = static_cast<unsigned int>(destArea.height); |
| parametersOut->PositionOffset[0] = |
| texelCenterX + (destArea.x / float(destSize.width)) * 2.0f - 1.0f; |
| parametersOut->PositionOffset[1] = |
| texelCenterY + ((destSize.height - destArea.y - 1) / float(destSize.height)) * 2.0f - 1.0f; |
| parametersOut->PositionScale[0] = 2.0f / static_cast<float>(destSize.width); |
| parametersOut->PositionScale[1] = -2.0f / static_cast<float>(destSize.height); |
| parametersOut->FirstSlice = destArea.z; |
| } |
| |
| angle::Result PixelTransfer11::copyBufferToTexture(const gl::Context *context, |
| const gl::PixelUnpackState &unpack, |
| unsigned int offset, |
| RenderTargetD3D *destRenderTarget, |
| GLenum destinationFormat, |
| GLenum sourcePixelsType, |
| const gl::Box &destArea) |
| { |
| ANGLE_TRY(loadResources(context)); |
| |
| gl::Extents destSize = destRenderTarget->getExtents(); |
| |
| ASSERT(destArea.x >= 0 && destArea.x + destArea.width <= destSize.width && destArea.y >= 0 && |
| destArea.y + destArea.height <= destSize.height && destArea.z >= 0 && |
| destArea.z + destArea.depth <= destSize.depth); |
| |
| const gl::Buffer &sourceBuffer = |
| *context->getState().getTargetBuffer(gl::BufferBinding::PixelUnpack); |
| |
| ASSERT(mRenderer->supportsFastCopyBufferToTexture(destinationFormat)); |
| |
| const d3d11::PixelShader *pixelShader = findBufferToTexturePS(destinationFormat); |
| ASSERT(pixelShader); |
| |
| // The SRV must be in the proper read format, which may be different from the destination format |
| // EG: for half float data, we can load full precision floats with implicit conversion |
| GLenum unsizedFormat = gl::GetUnsizedFormat(destinationFormat); |
| const gl::InternalFormat &sourceglFormatInfo = |
| gl::GetInternalFormatInfo(unsizedFormat, sourcePixelsType); |
| |
| const d3d11::Format &sourceFormatInfo = d3d11::Format::Get( |
| sourceglFormatInfo.sizedInternalFormat, mRenderer->getRenderer11DeviceCaps()); |
| DXGI_FORMAT srvFormat = sourceFormatInfo.srvFormat; |
| ASSERT(srvFormat != DXGI_FORMAT_UNKNOWN); |
| Buffer11 *bufferStorage11 = GetAs<Buffer11>(sourceBuffer.getImplementation()); |
| const d3d11::ShaderResourceView *bufferSRV = nullptr; |
| ANGLE_TRY(bufferStorage11->getSRV(context, srvFormat, &bufferSRV)); |
| ASSERT(bufferSRV != nullptr); |
| |
| const d3d11::RenderTargetView &textureRTV = |
| GetAs<RenderTarget11>(destRenderTarget)->getRenderTargetView(); |
| ASSERT(textureRTV.valid()); |
| |
| CopyShaderParams shaderParams; |
| setBufferToTextureCopyParams(destArea, destSize, sourceglFormatInfo.sizedInternalFormat, unpack, |
| offset, &shaderParams); |
| |
| ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); |
| |
| // Are we doing a 2D or 3D copy? |
| const auto *geometryShader = ((destSize.depth > 1) ? &mBufferToTextureGS : nullptr); |
| StateManager11 *stateManager = mRenderer->getStateManager(); |
| |
| stateManager->setDrawShaders(&mBufferToTextureVS, geometryShader, pixelShader); |
| stateManager->setShaderResource(gl::ShaderType::Fragment, 0, bufferSRV); |
| stateManager->setInputLayout(nullptr); |
| stateManager->setPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); |
| |
| stateManager->setSingleVertexBuffer(nullptr, 0, 0); |
| stateManager->setSimpleBlendState(nullptr); |
| stateManager->setDepthStencilState(&mCopyDepthStencilState, 0xFFFFFFFF); |
| stateManager->setRasterizerState(&mCopyRasterizerState); |
| |
| stateManager->setRenderTarget(textureRTV.get(), nullptr); |
| |
| if (!StructEquals(mParamsData, shaderParams)) |
| { |
| d3d11::SetBufferData(deviceContext, mParamsConstantBuffer.get(), shaderParams); |
| mParamsData = shaderParams; |
| } |
| |
| stateManager->setVertexConstantBuffer(0, &mParamsConstantBuffer); |
| |
| // Set the viewport |
| stateManager->setSimpleViewport(destSize); |
| |
| UINT numPixels = (destArea.width * destArea.height * destArea.depth); |
| deviceContext->Draw(numPixels, 0); |
| |
| return angle::Result::Continue; |
| } |
| |
| angle::Result PixelTransfer11::buildShaderMap(const gl::Context *context) |
| { |
| d3d11::PixelShader bufferToTextureFloat; |
| d3d11::PixelShader bufferToTextureInt; |
| d3d11::PixelShader bufferToTextureUint; |
| |
| Context11 *context11 = GetImplAs<Context11>(context); |
| |
| ANGLE_TRY(mRenderer->allocateResource(context11, ShaderData(g_PS_BufferToTexture_4F), |
| &bufferToTextureFloat)); |
| ANGLE_TRY(mRenderer->allocateResource(context11, ShaderData(g_PS_BufferToTexture_4I), |
| &bufferToTextureInt)); |
| ANGLE_TRY(mRenderer->allocateResource(context11, ShaderData(g_PS_BufferToTexture_4UI), |
| &bufferToTextureUint)); |
| |
| bufferToTextureFloat.setDebugName("BufferToTexture RGBA ps"); |
| bufferToTextureInt.setDebugName("BufferToTexture RGBA-I ps"); |
| bufferToTextureUint.setDebugName("BufferToTexture RGBA-UI ps"); |
| |
| mBufferToTexturePSMap[GL_FLOAT] = std::move(bufferToTextureFloat); |
| mBufferToTexturePSMap[GL_INT] = std::move(bufferToTextureInt); |
| mBufferToTexturePSMap[GL_UNSIGNED_INT] = std::move(bufferToTextureUint); |
| |
| return angle::Result::Continue; |
| } |
| |
| const d3d11::PixelShader *PixelTransfer11::findBufferToTexturePS(GLenum internalFormat) const |
| { |
| GLenum componentType = gl::GetSizedInternalFormatInfo(internalFormat).componentType; |
| if (componentType == GL_SIGNED_NORMALIZED || componentType == GL_UNSIGNED_NORMALIZED) |
| { |
| componentType = GL_FLOAT; |
| } |
| |
| auto shaderMapIt = mBufferToTexturePSMap.find(componentType); |
| return (shaderMapIt == mBufferToTexturePSMap.end() ? nullptr : &shaderMapIt->second); |
| } |
| |
| } // namespace rx |