blob: e5c55a845f7e1485b3602e9ad9513be2e78c8e48 [file] [log] [blame]
//
// 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