| // |
| // 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. |
| // |
| |
| // Blit11.cpp: Texture copy utility class. |
| |
| #include "libANGLE/renderer/d3d/d3d11/Blit11.h" |
| |
| #include <float.h> |
| |
| #include "common/utilities.h" |
| #include "libANGLE/Context.h" |
| #include "libANGLE/formatutils.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/formatutils11.h" |
| #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" |
| #include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" |
| #include "libANGLE/trace.h" |
| |
| namespace rx |
| { |
| |
| namespace |
| { |
| |
| // Include inline shaders in the anonymous namespace to make sure no symbols are exported |
| #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthrough2d11vs.h" |
| #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughdepth2d11ps.h" |
| |
| #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthrough3d11gs.h" |
| #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthrough3d11vs.h" |
| |
| #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/resolvedepth11_ps.h" |
| #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/resolvedepthstencil11_ps.h" |
| #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/resolvedepthstencil11_vs.h" |
| #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/resolvestencil11_ps.h" |
| |
| #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlef2darrayps.h" |
| #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlef2dps.h" |
| #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlef3dps.h" |
| #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlei2darrayps.h" |
| #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlei2dps.h" |
| #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlei3dps.h" |
| #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzleui2darrayps.h" |
| #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzleui2dps.h" |
| #include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzleui3dps.h" |
| |
| void StretchedBlitNearest_RowByRow(const gl::Box &sourceArea, |
| const gl::Box &destArea, |
| const gl::Rectangle &clippedDestArea, |
| const gl::Extents &sourceSize, |
| unsigned int sourceRowPitch, |
| unsigned int destRowPitch, |
| size_t pixelSize, |
| const uint8_t *sourceData, |
| uint8_t *destData) |
| { |
| int srcHeightSubOne = (sourceArea.height - 1); |
| size_t copySize = pixelSize * destArea.width; |
| size_t srcOffset = sourceArea.x * pixelSize; |
| size_t destOffset = destArea.x * pixelSize; |
| |
| for (int y = clippedDestArea.y; y < clippedDestArea.y + clippedDestArea.height; y++) |
| { |
| float yPerc = static_cast<float>(y - destArea.y) / (destArea.height - 1); |
| |
| // Interpolate using the original source rectangle to determine which row to sample from |
| // while clamping to the edges |
| unsigned int readRow = static_cast<unsigned int>( |
| gl::clamp(sourceArea.y + floor(yPerc * srcHeightSubOne + 0.5f), 0, srcHeightSubOne)); |
| unsigned int writeRow = y; |
| |
| const uint8_t *sourceRow = sourceData + readRow * sourceRowPitch + srcOffset; |
| uint8_t *destRow = destData + writeRow * destRowPitch + destOffset; |
| memcpy(destRow, sourceRow, copySize); |
| } |
| } |
| |
| void StretchedBlitNearest_PixelByPixel(const gl::Box &sourceArea, |
| const gl::Box &destArea, |
| const gl::Rectangle &clippedDestArea, |
| const gl::Extents &sourceSize, |
| unsigned int sourceRowPitch, |
| unsigned int destRowPitch, |
| ptrdiff_t readOffset, |
| ptrdiff_t writeOffset, |
| size_t copySize, |
| size_t srcPixelStride, |
| size_t destPixelStride, |
| const uint8_t *sourceData, |
| uint8_t *destData) |
| { |
| auto xMax = clippedDestArea.x + clippedDestArea.width; |
| auto yMax = clippedDestArea.y + clippedDestArea.height; |
| |
| for (int writeRow = clippedDestArea.y; writeRow < yMax; writeRow++) |
| { |
| // Interpolate using the original source rectangle to determine which row to sample from |
| // while clamping to the edges |
| float yPerc = static_cast<float>(writeRow - destArea.y) / (destArea.height - 1); |
| float yRounded = floor(yPerc * (sourceArea.height - 1) + 0.5f); |
| unsigned int readRow = |
| static_cast<unsigned int>(gl::clamp(sourceArea.y + yRounded, 0, sourceSize.height - 1)); |
| |
| for (int writeColumn = clippedDestArea.x; writeColumn < xMax; writeColumn++) |
| { |
| // Interpolate the original source rectangle to determine which column to sample |
| // from while clamping to the edges |
| float xPerc = static_cast<float>(writeColumn - destArea.x) / (destArea.width - 1); |
| float xRounded = floor(xPerc * (sourceArea.width - 1) + 0.5f); |
| unsigned int readColumn = static_cast<unsigned int>( |
| gl::clamp(sourceArea.x + xRounded, 0, sourceSize.height - 1)); |
| |
| const uint8_t *sourcePixel = |
| sourceData + readRow * sourceRowPitch + readColumn * srcPixelStride + readOffset; |
| |
| uint8_t *destPixel = |
| destData + writeRow * destRowPitch + writeColumn * destPixelStride + writeOffset; |
| |
| memcpy(destPixel, sourcePixel, copySize); |
| } |
| } |
| } |
| |
| void StretchedBlitNearest(const gl::Box &sourceArea, |
| const gl::Box &destArea, |
| const gl::Rectangle &clipRect, |
| const gl::Extents &sourceSize, |
| unsigned int sourceRowPitch, |
| unsigned int destRowPitch, |
| ptrdiff_t readOffset, |
| ptrdiff_t writeOffset, |
| size_t copySize, |
| size_t srcPixelStride, |
| size_t destPixelStride, |
| const uint8_t *sourceData, |
| uint8_t *destData) |
| { |
| gl::Rectangle clippedDestArea(destArea.x, destArea.y, destArea.width, destArea.height); |
| gl::ClipRectangle(clippedDestArea, clipRect, &clippedDestArea); |
| |
| // Determine if entire rows can be copied at once instead of each individual pixel. There |
| // must be no out of bounds lookups, whole rows copies, and no scale. |
| if (sourceArea.width == clippedDestArea.width && sourceArea.x >= 0 && |
| sourceArea.x + sourceArea.width <= sourceSize.width && copySize == srcPixelStride && |
| copySize == destPixelStride) |
| { |
| StretchedBlitNearest_RowByRow(sourceArea, destArea, clippedDestArea, sourceSize, |
| sourceRowPitch, destRowPitch, srcPixelStride, sourceData, |
| destData); |
| } |
| else |
| { |
| StretchedBlitNearest_PixelByPixel(sourceArea, destArea, clippedDestArea, sourceSize, |
| sourceRowPitch, destRowPitch, readOffset, writeOffset, |
| copySize, srcPixelStride, destPixelStride, sourceData, |
| destData); |
| } |
| } |
| |
| using DepthStencilLoader = void(const float *, uint8_t *); |
| |
| void LoadDepth16(const float *source, uint8_t *dest) |
| { |
| uint32_t convertedDepth = gl::floatToNormalized<16, uint32_t>(source[0]); |
| memcpy(dest, &convertedDepth, 2u); |
| } |
| |
| void LoadDepth24(const float *source, uint8_t *dest) |
| { |
| uint32_t convertedDepth = gl::floatToNormalized<24, uint32_t>(source[0]); |
| memcpy(dest, &convertedDepth, 3u); |
| } |
| |
| void LoadStencilHelper(const float *source, uint8_t *dest) |
| { |
| uint32_t convertedStencil = gl::getShiftedData<8, 0>(static_cast<uint32_t>(source[1])); |
| memcpy(dest, &convertedStencil, 1u); |
| } |
| |
| void LoadStencil8(const float *source, uint8_t *dest) |
| { |
| // STENCIL_INDEX8 is implemented with D24S8, with the depth bits unused. Writes zero for safety. |
| float zero = 0.0f; |
| LoadDepth24(&zero, &dest[0]); |
| LoadStencilHelper(source, &dest[3]); |
| } |
| |
| void LoadDepth24Stencil8(const float *source, uint8_t *dest) |
| { |
| LoadDepth24(source, &dest[0]); |
| LoadStencilHelper(source, &dest[3]); |
| } |
| |
| void LoadDepth32F(const float *source, uint8_t *dest) |
| { |
| memcpy(dest, source, sizeof(float)); |
| } |
| |
| void LoadDepth32FStencil8(const float *source, uint8_t *dest) |
| { |
| LoadDepth32F(source, &dest[0]); |
| LoadStencilHelper(source, &dest[4]); |
| } |
| |
| template <DepthStencilLoader loader> |
| void CopyDepthStencil(const gl::Box &sourceArea, |
| const gl::Box &destArea, |
| const gl::Rectangle &clippedDestArea, |
| const gl::Extents &sourceSize, |
| unsigned int sourceRowPitch, |
| unsigned int destRowPitch, |
| ptrdiff_t readOffset, |
| ptrdiff_t writeOffset, |
| size_t copySize, |
| size_t srcPixelStride, |
| size_t destPixelStride, |
| const uint8_t *sourceData, |
| uint8_t *destData) |
| { |
| // No stretching or subregions are supported, only full blits. |
| ASSERT(sourceArea == destArea); |
| ASSERT(sourceSize.width == sourceArea.width && sourceSize.height == sourceArea.height && |
| sourceSize.depth == 1); |
| ASSERT(clippedDestArea.width == sourceSize.width && |
| clippedDestArea.height == sourceSize.height); |
| ASSERT(readOffset == 0 && writeOffset == 0); |
| ASSERT(destArea.x == 0 && destArea.y == 0); |
| |
| for (int row = 0; row < destArea.height; ++row) |
| { |
| for (int column = 0; column < destArea.width; ++column) |
| { |
| ptrdiff_t offset = row * sourceRowPitch + column * srcPixelStride; |
| const float *sourcePixel = reinterpret_cast<const float *>(sourceData + offset); |
| |
| uint8_t *destPixel = destData + row * destRowPitch + column * destPixelStride; |
| |
| loader(sourcePixel, destPixel); |
| } |
| } |
| } |
| |
| void Depth32FStencil8ToDepth32F(const float *source, float *dest) |
| { |
| *dest = *source; |
| } |
| |
| void Depth24Stencil8ToDepth32F(const uint32_t *source, float *dest) |
| { |
| uint32_t normDepth = source[0] & 0x00FFFFFF; |
| float floatDepth = gl::normalizedToFloat<24>(normDepth); |
| *dest = floatDepth; |
| } |
| |
| void BlitD24S8ToD32F(const gl::Box &sourceArea, |
| const gl::Box &destArea, |
| const gl::Rectangle &clippedDestArea, |
| const gl::Extents &sourceSize, |
| unsigned int sourceRowPitch, |
| unsigned int destRowPitch, |
| ptrdiff_t readOffset, |
| ptrdiff_t writeOffset, |
| size_t copySize, |
| size_t srcPixelStride, |
| size_t destPixelStride, |
| const uint8_t *sourceData, |
| uint8_t *destData) |
| { |
| // No stretching or subregions are supported, only full blits. |
| ASSERT(sourceArea == destArea); |
| ASSERT(sourceSize.width == sourceArea.width && sourceSize.height == sourceArea.height && |
| sourceSize.depth == 1); |
| ASSERT(clippedDestArea.width == sourceSize.width && |
| clippedDestArea.height == sourceSize.height); |
| ASSERT(readOffset == 0 && writeOffset == 0); |
| ASSERT(destArea.x == 0 && destArea.y == 0); |
| |
| for (int row = 0; row < destArea.height; ++row) |
| { |
| for (int column = 0; column < destArea.width; ++column) |
| { |
| ptrdiff_t offset = row * sourceRowPitch + column * srcPixelStride; |
| const uint32_t *sourcePixel = reinterpret_cast<const uint32_t *>(sourceData + offset); |
| |
| float *destPixel = |
| reinterpret_cast<float *>(destData + row * destRowPitch + column * destPixelStride); |
| |
| Depth24Stencil8ToDepth32F(sourcePixel, destPixel); |
| } |
| } |
| } |
| |
| void BlitD32FS8ToD32F(const gl::Box &sourceArea, |
| const gl::Box &destArea, |
| const gl::Rectangle &clippedDestArea, |
| const gl::Extents &sourceSize, |
| unsigned int sourceRowPitch, |
| unsigned int destRowPitch, |
| ptrdiff_t readOffset, |
| ptrdiff_t writeOffset, |
| size_t copySize, |
| size_t srcPixelStride, |
| size_t destPixelStride, |
| const uint8_t *sourceData, |
| uint8_t *destData) |
| { |
| // No stretching or subregions are supported, only full blits. |
| ASSERT(sourceArea == destArea); |
| ASSERT(sourceSize.width == sourceArea.width && sourceSize.height == sourceArea.height && |
| sourceSize.depth == 1); |
| ASSERT(clippedDestArea.width == sourceSize.width && |
| clippedDestArea.height == sourceSize.height); |
| ASSERT(readOffset == 0 && writeOffset == 0); |
| ASSERT(destArea.x == 0 && destArea.y == 0); |
| |
| for (int row = 0; row < destArea.height; ++row) |
| { |
| for (int column = 0; column < destArea.width; ++column) |
| { |
| ptrdiff_t offset = row * sourceRowPitch + column * srcPixelStride; |
| const float *sourcePixel = reinterpret_cast<const float *>(sourceData + offset); |
| float *destPixel = |
| reinterpret_cast<float *>(destData + row * destRowPitch + column * destPixelStride); |
| |
| Depth32FStencil8ToDepth32F(sourcePixel, destPixel); |
| } |
| } |
| } |
| |
| Blit11::BlitConvertFunction *GetCopyDepthStencilFunction(GLenum internalFormat) |
| { |
| switch (internalFormat) |
| { |
| case GL_DEPTH_COMPONENT16: |
| return &CopyDepthStencil<LoadDepth16>; |
| case GL_DEPTH_COMPONENT24: |
| return &CopyDepthStencil<LoadDepth24>; |
| case GL_DEPTH_COMPONENT32F: |
| return &CopyDepthStencil<LoadDepth32F>; |
| case GL_STENCIL_INDEX8: |
| return &CopyDepthStencil<LoadStencil8>; |
| case GL_DEPTH24_STENCIL8: |
| return &CopyDepthStencil<LoadDepth24Stencil8>; |
| case GL_DEPTH32F_STENCIL8: |
| return &CopyDepthStencil<LoadDepth32FStencil8>; |
| default: |
| UNREACHABLE(); |
| return nullptr; |
| } |
| } |
| |
| inline void GenerateVertexCoords(const gl::Box &sourceArea, |
| const gl::Extents &sourceSize, |
| const gl::Box &destArea, |
| const gl::Extents &destSize, |
| float *x1, |
| float *y1, |
| float *x2, |
| float *y2, |
| float *u1, |
| float *v1, |
| float *u2, |
| float *v2) |
| { |
| *x1 = (destArea.x / float(destSize.width)) * 2.0f - 1.0f; |
| *y1 = ((destSize.height - destArea.y - destArea.height) / float(destSize.height)) * 2.0f - 1.0f; |
| *x2 = ((destArea.x + destArea.width) / float(destSize.width)) * 2.0f - 1.0f; |
| *y2 = ((destSize.height - destArea.y) / float(destSize.height)) * 2.0f - 1.0f; |
| |
| *u1 = sourceArea.x / float(sourceSize.width); |
| *v1 = sourceArea.y / float(sourceSize.height); |
| *u2 = (sourceArea.x + sourceArea.width) / float(sourceSize.width); |
| *v2 = (sourceArea.y + sourceArea.height) / float(sourceSize.height); |
| } |
| |
| void Write2DVertices(const gl::Box &sourceArea, |
| const gl::Extents &sourceSize, |
| const gl::Box &destArea, |
| const gl::Extents &destSize, |
| void *outVertices, |
| unsigned int *outStride, |
| unsigned int *outVertexCount, |
| D3D11_PRIMITIVE_TOPOLOGY *outTopology) |
| { |
| float x1, y1, x2, y2, u1, v1, u2, v2; |
| GenerateVertexCoords(sourceArea, sourceSize, destArea, destSize, &x1, &y1, &x2, &y2, &u1, &v1, |
| &u2, &v2); |
| |
| d3d11::PositionTexCoordVertex *vertices = |
| static_cast<d3d11::PositionTexCoordVertex *>(outVertices); |
| |
| d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, u1, v2); |
| d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, u1, v1); |
| d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, u2, v2); |
| d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, u2, v1); |
| |
| *outStride = sizeof(d3d11::PositionTexCoordVertex); |
| *outVertexCount = 4; |
| *outTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; |
| } |
| |
| void Write3DVertices(const gl::Box &sourceArea, |
| const gl::Extents &sourceSize, |
| const gl::Box &destArea, |
| const gl::Extents &destSize, |
| void *outVertices, |
| unsigned int *outStride, |
| unsigned int *outVertexCount, |
| D3D11_PRIMITIVE_TOPOLOGY *outTopology) |
| { |
| ASSERT(sourceSize.depth > 0 && destSize.depth > 0); |
| |
| float x1, y1, x2, y2, u1, v1, u2, v2; |
| GenerateVertexCoords(sourceArea, sourceSize, destArea, destSize, &x1, &y1, &x2, &y2, &u1, &v1, |
| &u2, &v2); |
| |
| d3d11::PositionLayerTexCoord3DVertex *vertices = |
| static_cast<d3d11::PositionLayerTexCoord3DVertex *>(outVertices); |
| |
| for (int i = 0; i < destSize.depth; i++) |
| { |
| float readDepth = (float)i / std::max(destSize.depth - 1, 1); |
| |
| d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 0], x1, y1, i, u1, v2, readDepth); |
| d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 1], x1, y2, i, u1, v1, readDepth); |
| d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 2], x2, y1, i, u2, v2, readDepth); |
| |
| d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 3], x1, y2, i, u1, v1, readDepth); |
| d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 4], x2, y2, i, u2, v1, readDepth); |
| d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 5], x2, y1, i, u2, v2, readDepth); |
| } |
| |
| *outStride = sizeof(d3d11::PositionLayerTexCoord3DVertex); |
| *outVertexCount = destSize.depth * 6; |
| *outTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; |
| } |
| |
| unsigned int GetSwizzleIndex(GLenum swizzle) |
| { |
| unsigned int colorIndex = 0; |
| |
| switch (swizzle) |
| { |
| case GL_RED: |
| colorIndex = 0; |
| break; |
| case GL_GREEN: |
| colorIndex = 1; |
| break; |
| case GL_BLUE: |
| colorIndex = 2; |
| break; |
| case GL_ALPHA: |
| colorIndex = 3; |
| break; |
| case GL_ZERO: |
| colorIndex = 4; |
| break; |
| case GL_ONE: |
| colorIndex = 5; |
| break; |
| default: |
| UNREACHABLE(); |
| break; |
| } |
| |
| return colorIndex; |
| } |
| |
| D3D11_BLEND_DESC GetAlphaMaskBlendStateDesc() |
| { |
| D3D11_BLEND_DESC desc; |
| memset(&desc, 0, sizeof(desc)); |
| desc.RenderTarget[0].BlendEnable = TRUE; |
| desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; |
| desc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO; |
| desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; |
| desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ZERO; |
| desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; |
| desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; |
| desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_RED | |
| D3D11_COLOR_WRITE_ENABLE_GREEN | |
| D3D11_COLOR_WRITE_ENABLE_BLUE; |
| return desc; |
| } |
| |
| D3D11_INPUT_ELEMENT_DESC quad2DLayout[] = { |
| {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, |
| {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0}, |
| }; |
| |
| D3D11_INPUT_ELEMENT_DESC quad3DLayout[] = { |
| {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, |
| {"LAYER", 0, DXGI_FORMAT_R32_UINT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0}, |
| {"TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}, |
| }; |
| |
| DXGI_FORMAT GetStencilSRVFormat(const d3d11::Format &formatSet) |
| { |
| switch (formatSet.texFormat) |
| { |
| case DXGI_FORMAT_R32G8X24_TYPELESS: |
| return DXGI_FORMAT_X32_TYPELESS_G8X24_UINT; |
| case DXGI_FORMAT_R24G8_TYPELESS: |
| return DXGI_FORMAT_X24_TYPELESS_G8_UINT; |
| default: |
| UNREACHABLE(); |
| return DXGI_FORMAT_UNKNOWN; |
| } |
| } |
| |
| } // namespace |
| |
| #include "libANGLE/renderer/d3d/d3d11/Blit11Helper_autogen.inc" |
| |
| Blit11::Shader::Shader() = default; |
| |
| Blit11::Shader::Shader(Shader &&other) = default; |
| |
| Blit11::Shader::~Shader() = default; |
| |
| Blit11::Shader &Blit11::Shader::operator=(Blit11::Shader &&other) = default; |
| |
| Blit11::Blit11(Renderer11 *renderer) |
| : mRenderer(renderer), |
| mResourcesInitialized(false), |
| mVertexBuffer(), |
| mPointSampler(), |
| mLinearSampler(), |
| mScissorEnabledRasterizerState(), |
| mScissorDisabledRasterizerState(), |
| mDepthStencilState(), |
| mQuad2DIL(quad2DLayout, |
| ArraySize(quad2DLayout), |
| g_VS_Passthrough2D, |
| ArraySize(g_VS_Passthrough2D), |
| "Blit11 2D input layout"), |
| mQuad2DVS(g_VS_Passthrough2D, ArraySize(g_VS_Passthrough2D), "Blit11 2D vertex shader"), |
| mDepthPS(g_PS_PassthroughDepth2D, |
| ArraySize(g_PS_PassthroughDepth2D), |
| "Blit11 2D depth pixel shader"), |
| mQuad3DIL(quad3DLayout, |
| ArraySize(quad3DLayout), |
| g_VS_Passthrough3D, |
| ArraySize(g_VS_Passthrough3D), |
| "Blit11 3D input layout"), |
| mQuad3DVS(g_VS_Passthrough3D, ArraySize(g_VS_Passthrough3D), "Blit11 3D vertex shader"), |
| mQuad3DGS(g_GS_Passthrough3D, ArraySize(g_GS_Passthrough3D), "Blit11 3D geometry shader"), |
| mAlphaMaskBlendState(GetAlphaMaskBlendStateDesc(), "Blit11 Alpha Mask Blend"), |
| mSwizzleCB(), |
| mResolveDepthStencilVS(g_VS_ResolveDepthStencil, |
| ArraySize(g_VS_ResolveDepthStencil), |
| "Blit11::mResolveDepthStencilVS"), |
| mResolveDepthPS(g_PS_ResolveDepth, ArraySize(g_PS_ResolveDepth), "Blit11::mResolveDepthPS"), |
| mResolveDepthStencilPS(g_PS_ResolveDepthStencil, |
| ArraySize(g_PS_ResolveDepthStencil), |
| "Blit11::mResolveDepthStencilPS"), |
| mResolveStencilPS(g_PS_ResolveStencil, |
| ArraySize(g_PS_ResolveStencil), |
| "Blit11::mResolveStencilPS"), |
| mStencilSRV(), |
| mResolvedDepthStencilRTView() |
| {} |
| |
| Blit11::~Blit11() {} |
| |
| angle::Result Blit11::initResources(const gl::Context *context) |
| { |
| if (mResourcesInitialized) |
| { |
| return angle::Result::Continue; |
| } |
| |
| ANGLE_TRACE_EVENT0("gpu.angle", "Blit11::initResources"); |
| |
| D3D11_BUFFER_DESC vbDesc; |
| vbDesc.ByteWidth = |
| static_cast<unsigned int>(std::max(sizeof(d3d11::PositionLayerTexCoord3DVertex), |
| sizeof(d3d11::PositionTexCoordVertex)) * |
| 6 * mRenderer->getNativeCaps().max3DTextureSize); |
| vbDesc.Usage = D3D11_USAGE_DYNAMIC; |
| vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; |
| vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; |
| vbDesc.MiscFlags = 0; |
| vbDesc.StructureByteStride = 0; |
| |
| Context11 *context11 = GetImplAs<Context11>(context); |
| |
| ANGLE_TRY(mRenderer->allocateResource(context11, vbDesc, &mVertexBuffer)); |
| mVertexBuffer.setDebugName("Blit11 vertex buffer"); |
| |
| D3D11_SAMPLER_DESC pointSamplerDesc; |
| pointSamplerDesc.Filter = D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR; |
| pointSamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; |
| pointSamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; |
| pointSamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; |
| pointSamplerDesc.MipLODBias = 0.0f; |
| pointSamplerDesc.MaxAnisotropy = 0; |
| pointSamplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; |
| pointSamplerDesc.BorderColor[0] = 0.0f; |
| pointSamplerDesc.BorderColor[1] = 0.0f; |
| pointSamplerDesc.BorderColor[2] = 0.0f; |
| pointSamplerDesc.BorderColor[3] = 0.0f; |
| pointSamplerDesc.MinLOD = 0.0f; |
| pointSamplerDesc.MaxLOD = FLT_MAX; |
| |
| ANGLE_TRY(mRenderer->allocateResource(context11, pointSamplerDesc, &mPointSampler)); |
| mPointSampler.setDebugName("Blit11 point sampler"); |
| |
| D3D11_SAMPLER_DESC linearSamplerDesc; |
| linearSamplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; |
| linearSamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; |
| linearSamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; |
| linearSamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; |
| linearSamplerDesc.MipLODBias = 0.0f; |
| linearSamplerDesc.MaxAnisotropy = 0; |
| linearSamplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; |
| linearSamplerDesc.BorderColor[0] = 0.0f; |
| linearSamplerDesc.BorderColor[1] = 0.0f; |
| linearSamplerDesc.BorderColor[2] = 0.0f; |
| linearSamplerDesc.BorderColor[3] = 0.0f; |
| linearSamplerDesc.MinLOD = 0.0f; |
| linearSamplerDesc.MaxLOD = FLT_MAX; |
| |
| ANGLE_TRY(mRenderer->allocateResource(context11, linearSamplerDesc, &mLinearSampler)); |
| mLinearSampler.setDebugName("Blit11 linear sampler"); |
| |
| // Use a rasterizer state that will not cull so that inverted quads will not be culled |
| 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.MultisampleEnable = FALSE; |
| rasterDesc.AntialiasedLineEnable = FALSE; |
| |
| rasterDesc.ScissorEnable = TRUE; |
| ANGLE_TRY(mRenderer->allocateResource(context11, rasterDesc, &mScissorEnabledRasterizerState)); |
| mScissorEnabledRasterizerState.setDebugName("Blit11 scissoring rasterizer state"); |
| |
| rasterDesc.ScissorEnable = FALSE; |
| ANGLE_TRY(mRenderer->allocateResource(context11, rasterDesc, &mScissorDisabledRasterizerState)); |
| mScissorDisabledRasterizerState.setDebugName("Blit11 no scissoring rasterizer state"); |
| |
| 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, &mDepthStencilState)); |
| mDepthStencilState.setDebugName("Blit11 depth stencil state"); |
| |
| D3D11_BUFFER_DESC swizzleBufferDesc; |
| swizzleBufferDesc.ByteWidth = sizeof(unsigned int) * 4; |
| swizzleBufferDesc.Usage = D3D11_USAGE_DYNAMIC; |
| swizzleBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; |
| swizzleBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; |
| swizzleBufferDesc.MiscFlags = 0; |
| swizzleBufferDesc.StructureByteStride = 0; |
| |
| ANGLE_TRY(mRenderer->allocateResource(context11, swizzleBufferDesc, &mSwizzleCB)); |
| mSwizzleCB.setDebugName("Blit11 swizzle constant buffer"); |
| |
| mResourcesInitialized = true; |
| |
| return angle::Result::Continue; |
| } |
| |
| // static |
| Blit11::SwizzleShaderType Blit11::GetSwizzleShaderType(GLenum type, |
| D3D11_SRV_DIMENSION dimensionality) |
| { |
| switch (dimensionality) |
| { |
| case D3D11_SRV_DIMENSION_TEXTURE2D: |
| switch (type) |
| { |
| case GL_FLOAT: |
| return SWIZZLESHADER_2D_FLOAT; |
| case GL_UNSIGNED_INT: |
| return SWIZZLESHADER_2D_UINT; |
| case GL_INT: |
| return SWIZZLESHADER_2D_INT; |
| default: |
| UNREACHABLE(); |
| return SWIZZLESHADER_INVALID; |
| } |
| case D3D11_SRV_DIMENSION_TEXTURECUBE: |
| switch (type) |
| { |
| case GL_FLOAT: |
| return SWIZZLESHADER_CUBE_FLOAT; |
| case GL_UNSIGNED_INT: |
| return SWIZZLESHADER_CUBE_UINT; |
| case GL_INT: |
| return SWIZZLESHADER_CUBE_INT; |
| default: |
| UNREACHABLE(); |
| return SWIZZLESHADER_INVALID; |
| } |
| case D3D11_SRV_DIMENSION_TEXTURE3D: |
| switch (type) |
| { |
| case GL_FLOAT: |
| return SWIZZLESHADER_3D_FLOAT; |
| case GL_UNSIGNED_INT: |
| return SWIZZLESHADER_3D_UINT; |
| case GL_INT: |
| return SWIZZLESHADER_3D_INT; |
| default: |
| UNREACHABLE(); |
| return SWIZZLESHADER_INVALID; |
| } |
| case D3D11_SRV_DIMENSION_TEXTURE2DARRAY: |
| switch (type) |
| { |
| case GL_FLOAT: |
| return SWIZZLESHADER_ARRAY_FLOAT; |
| case GL_UNSIGNED_INT: |
| return SWIZZLESHADER_ARRAY_UINT; |
| case GL_INT: |
| return SWIZZLESHADER_ARRAY_INT; |
| default: |
| UNREACHABLE(); |
| return SWIZZLESHADER_INVALID; |
| } |
| default: |
| UNREACHABLE(); |
| return SWIZZLESHADER_INVALID; |
| } |
| } |
| |
| angle::Result Blit11::getShaderSupport(const gl::Context *context, |
| const Shader &shader, |
| Blit11::ShaderSupport *supportOut) |
| { |
| |
| Context11 *context11 = GetImplAs<Context11>(context); |
| |
| switch (shader.dimension) |
| { |
| case SHADER_2D: |
| { |
| ANGLE_TRY(mQuad2DIL.resolve(context11, mRenderer)); |
| ANGLE_TRY(mQuad2DVS.resolve(context11, mRenderer)); |
| supportOut->inputLayout = &mQuad2DIL.getObj(); |
| supportOut->vertexShader = &mQuad2DVS.getObj(); |
| supportOut->geometryShader = nullptr; |
| supportOut->vertexWriteFunction = Write2DVertices; |
| break; |
| } |
| case SHADER_3D: |
| case SHADER_2DARRAY: |
| { |
| ANGLE_TRY(mQuad3DIL.resolve(context11, mRenderer)); |
| ANGLE_TRY(mQuad3DVS.resolve(context11, mRenderer)); |
| ANGLE_TRY(mQuad3DGS.resolve(context11, mRenderer)); |
| supportOut->inputLayout = &mQuad3DIL.getObj(); |
| supportOut->vertexShader = &mQuad3DVS.getObj(); |
| supportOut->geometryShader = &mQuad3DGS.getObj(); |
| supportOut->vertexWriteFunction = Write3DVertices; |
| break; |
| } |
| default: |
| UNREACHABLE(); |
| } |
| |
| return angle::Result::Continue; |
| } |
| |
| angle::Result Blit11::swizzleTexture(const gl::Context *context, |
| const d3d11::SharedSRV &source, |
| const d3d11::RenderTargetView &dest, |
| const gl::Extents &size, |
| const gl::SwizzleState &swizzleTarget) |
| { |
| ANGLE_TRY(initResources(context)); |
| |
| ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); |
| |
| D3D11_SHADER_RESOURCE_VIEW_DESC sourceSRVDesc; |
| source.get()->GetDesc(&sourceSRVDesc); |
| |
| GLenum componentType = d3d11::GetComponentType(sourceSRVDesc.Format); |
| if (componentType == GL_NONE) |
| { |
| // We're swizzling the depth component of a depth-stencil texture. |
| switch (sourceSRVDesc.Format) |
| { |
| case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: |
| componentType = GL_UNSIGNED_NORMALIZED; |
| break; |
| case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: |
| componentType = GL_FLOAT; |
| break; |
| default: |
| UNREACHABLE(); |
| break; |
| } |
| } |
| |
| GLenum shaderType = GL_NONE; |
| switch (componentType) |
| { |
| case GL_UNSIGNED_NORMALIZED: |
| case GL_SIGNED_NORMALIZED: |
| case GL_FLOAT: |
| shaderType = GL_FLOAT; |
| break; |
| case GL_INT: |
| shaderType = GL_INT; |
| break; |
| case GL_UNSIGNED_INT: |
| shaderType = GL_UNSIGNED_INT; |
| break; |
| default: |
| UNREACHABLE(); |
| break; |
| } |
| |
| const Shader *shader = nullptr; |
| ANGLE_TRY(getSwizzleShader(context, shaderType, sourceSRVDesc.ViewDimension, &shader)); |
| |
| // Set vertices |
| D3D11_MAPPED_SUBRESOURCE mappedResource; |
| ANGLE_TRY(mRenderer->mapResource(context, mVertexBuffer.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, |
| &mappedResource)); |
| |
| ShaderSupport support; |
| ANGLE_TRY(getShaderSupport(context, *shader, &support)); |
| |
| UINT stride = 0; |
| UINT drawCount = 0; |
| D3D11_PRIMITIVE_TOPOLOGY topology; |
| |
| gl::Box area(0, 0, 0, size.width, size.height, size.depth); |
| support.vertexWriteFunction(area, size, area, size, mappedResource.pData, &stride, &drawCount, |
| &topology); |
| |
| deviceContext->Unmap(mVertexBuffer.get(), 0); |
| |
| // Set constant buffer |
| ANGLE_TRY(mRenderer->mapResource(context, mSwizzleCB.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, |
| &mappedResource)); |
| |
| unsigned int *swizzleIndices = static_cast<unsigned int *>(mappedResource.pData); |
| swizzleIndices[0] = GetSwizzleIndex(swizzleTarget.swizzleRed); |
| swizzleIndices[1] = GetSwizzleIndex(swizzleTarget.swizzleGreen); |
| swizzleIndices[2] = GetSwizzleIndex(swizzleTarget.swizzleBlue); |
| swizzleIndices[3] = GetSwizzleIndex(swizzleTarget.swizzleAlpha); |
| |
| deviceContext->Unmap(mSwizzleCB.get(), 0); |
| |
| StateManager11 *stateManager = mRenderer->getStateManager(); |
| |
| // Apply vertex buffer |
| stateManager->setSingleVertexBuffer(&mVertexBuffer, stride, 0); |
| |
| // Apply constant buffer |
| stateManager->setPixelConstantBuffer(0, &mSwizzleCB); |
| |
| // Apply state |
| stateManager->setSimpleBlendState(nullptr); |
| stateManager->setDepthStencilState(nullptr, 0xFFFFFFFF); |
| stateManager->setRasterizerState(&mScissorDisabledRasterizerState); |
| |
| // Apply shaders |
| stateManager->setInputLayout(support.inputLayout); |
| stateManager->setPrimitiveTopology(topology); |
| |
| stateManager->setDrawShaders(support.vertexShader, support.geometryShader, |
| &shader->pixelShader); |
| |
| // Apply render target |
| stateManager->setRenderTarget(dest.get(), nullptr); |
| |
| // Set the viewport |
| stateManager->setSimpleViewport(size); |
| |
| // Apply textures and sampler |
| stateManager->setSimplePixelTextureAndSampler(source, mPointSampler); |
| |
| // Draw the quad |
| deviceContext->Draw(drawCount, 0); |
| |
| return angle::Result::Continue; |
| } |
| |
| angle::Result Blit11::copyTexture(const gl::Context *context, |
| const d3d11::SharedSRV &source, |
| const gl::Box &sourceArea, |
| const gl::Extents &sourceSize, |
| GLenum sourceFormat, |
| const d3d11::RenderTargetView &dest, |
| const gl::Box &destArea, |
| const gl::Extents &destSize, |
| const gl::Rectangle *scissor, |
| GLenum destFormat, |
| GLenum destTypeForDownsampling, |
| GLenum filter, |
| bool maskOffAlpha, |
| bool unpackPremultiplyAlpha, |
| bool unpackUnmultiplyAlpha) |
| { |
| ANGLE_TRY(initResources(context)); |
| |
| ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); |
| |
| // Determine if the source format is a signed integer format, the destFormat will already |
| // be GL_XXXX_INTEGER but it does not tell us if it is signed or unsigned. |
| D3D11_SHADER_RESOURCE_VIEW_DESC sourceSRVDesc; |
| source.get()->GetDesc(&sourceSRVDesc); |
| |
| GLenum componentType = d3d11::GetComponentType(sourceSRVDesc.Format); |
| |
| ASSERT(componentType != GL_NONE); |
| ASSERT(componentType != GL_SIGNED_NORMALIZED); |
| bool isSrcSigned = (componentType == GL_INT); |
| |
| D3D11_RENDER_TARGET_VIEW_DESC destRTVDesc; |
| dest.get()->GetDesc(&destRTVDesc); |
| |
| GLenum destComponentType = d3d11::GetComponentType(destRTVDesc.Format); |
| |
| ASSERT(componentType != GL_NONE); |
| bool isDestSigned = (destComponentType == GL_INT); |
| |
| ShaderDimension dimension = SHADER_INVALID; |
| |
| switch (sourceSRVDesc.ViewDimension) |
| { |
| case D3D11_SRV_DIMENSION_TEXTURE2D: |
| dimension = SHADER_2D; |
| break; |
| case D3D11_SRV_DIMENSION_TEXTURE3D: |
| dimension = SHADER_3D; |
| break; |
| case D3D11_SRV_DIMENSION_TEXTURE2DARRAY: |
| dimension = SHADER_2DARRAY; |
| break; |
| default: |
| UNREACHABLE(); |
| } |
| |
| const Shader *shader = nullptr; |
| |
| ANGLE_TRY(getBlitShader(context, destFormat, sourceFormat, isSrcSigned, isDestSigned, |
| unpackPremultiplyAlpha, unpackUnmultiplyAlpha, destTypeForDownsampling, |
| dimension, &shader)); |
| |
| ShaderSupport support; |
| ANGLE_TRY(getShaderSupport(context, *shader, &support)); |
| |
| // Set vertices |
| D3D11_MAPPED_SUBRESOURCE mappedResource; |
| ANGLE_TRY(mRenderer->mapResource(context, mVertexBuffer.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, |
| &mappedResource)); |
| |
| UINT stride = 0; |
| UINT drawCount = 0; |
| D3D11_PRIMITIVE_TOPOLOGY topology; |
| |
| support.vertexWriteFunction(sourceArea, sourceSize, destArea, destSize, mappedResource.pData, |
| &stride, &drawCount, &topology); |
| |
| deviceContext->Unmap(mVertexBuffer.get(), 0); |
| |
| StateManager11 *stateManager = mRenderer->getStateManager(); |
| |
| // Apply vertex buffer |
| stateManager->setSingleVertexBuffer(&mVertexBuffer, stride, 0); |
| |
| // Apply state |
| if (maskOffAlpha) |
| { |
| ANGLE_TRY(mAlphaMaskBlendState.resolve(GetImplAs<Context11>(context), mRenderer)); |
| stateManager->setSimpleBlendState(&mAlphaMaskBlendState.getObj()); |
| } |
| else |
| { |
| stateManager->setSimpleBlendState(nullptr); |
| } |
| stateManager->setDepthStencilState(nullptr, 0xFFFFFFFF); |
| |
| if (scissor) |
| { |
| stateManager->setSimpleScissorRect(*scissor); |
| stateManager->setRasterizerState(&mScissorEnabledRasterizerState); |
| } |
| else |
| { |
| stateManager->setRasterizerState(&mScissorDisabledRasterizerState); |
| } |
| |
| // Apply shaders |
| stateManager->setInputLayout(support.inputLayout); |
| stateManager->setPrimitiveTopology(topology); |
| |
| stateManager->setDrawShaders(support.vertexShader, support.geometryShader, |
| &shader->pixelShader); |
| |
| // Apply render target |
| stateManager->setRenderTarget(dest.get(), nullptr); |
| |
| // Set the viewport |
| stateManager->setSimpleViewport(destSize); |
| |
| // Apply texture and sampler |
| switch (filter) |
| { |
| case GL_NEAREST: |
| stateManager->setSimplePixelTextureAndSampler(source, mPointSampler); |
| break; |
| case GL_LINEAR: |
| stateManager->setSimplePixelTextureAndSampler(source, mLinearSampler); |
| break; |
| |
| default: |
| UNREACHABLE(); |
| ANGLE_TRY_HR(GetImplAs<Context11>(context), E_FAIL, |
| "Internal error, unknown blit filter mode."); |
| } |
| |
| // Draw the quad |
| deviceContext->Draw(drawCount, 0); |
| |
| return angle::Result::Continue; |
| } |
| |
| angle::Result Blit11::copyStencil(const gl::Context *context, |
| const TextureHelper11 &source, |
| unsigned int sourceSubresource, |
| const gl::Box &sourceArea, |
| const gl::Extents &sourceSize, |
| const TextureHelper11 &dest, |
| unsigned int destSubresource, |
| const gl::Box &destArea, |
| const gl::Extents &destSize, |
| const gl::Rectangle *scissor) |
| { |
| return copyDepthStencilImpl(context, source, sourceSubresource, sourceArea, sourceSize, dest, |
| destSubresource, destArea, destSize, scissor, true); |
| } |
| |
| angle::Result Blit11::copyDepth(const gl::Context *context, |
| const d3d11::SharedSRV &source, |
| const gl::Box &sourceArea, |
| const gl::Extents &sourceSize, |
| const d3d11::DepthStencilView &dest, |
| const gl::Box &destArea, |
| const gl::Extents &destSize, |
| const gl::Rectangle *scissor) |
| { |
| ANGLE_TRY(initResources(context)); |
| |
| ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); |
| |
| // Set vertices |
| D3D11_MAPPED_SUBRESOURCE mappedResource; |
| ANGLE_TRY(mRenderer->mapResource(context, mVertexBuffer.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, |
| &mappedResource)); |
| |
| UINT stride = 0; |
| UINT drawCount = 0; |
| D3D11_PRIMITIVE_TOPOLOGY topology; |
| |
| Write2DVertices(sourceArea, sourceSize, destArea, destSize, mappedResource.pData, &stride, |
| &drawCount, &topology); |
| |
| deviceContext->Unmap(mVertexBuffer.get(), 0); |
| |
| StateManager11 *stateManager = mRenderer->getStateManager(); |
| |
| // Apply vertex buffer |
| stateManager->setSingleVertexBuffer(&mVertexBuffer, stride, 0); |
| |
| // Apply state |
| stateManager->setSimpleBlendState(nullptr); |
| stateManager->setDepthStencilState(&mDepthStencilState, 0xFFFFFFFF); |
| |
| if (scissor) |
| { |
| stateManager->setSimpleScissorRect(*scissor); |
| stateManager->setRasterizerState(&mScissorEnabledRasterizerState); |
| } |
| else |
| { |
| stateManager->setRasterizerState(&mScissorDisabledRasterizerState); |
| } |
| |
| Context11 *context11 = GetImplAs<Context11>(context); |
| |
| ANGLE_TRY(mQuad2DIL.resolve(context11, mRenderer)); |
| ANGLE_TRY(mQuad2DVS.resolve(context11, mRenderer)); |
| ANGLE_TRY(mDepthPS.resolve(context11, mRenderer)); |
| |
| // Apply shaders |
| stateManager->setInputLayout(&mQuad2DIL.getObj()); |
| stateManager->setPrimitiveTopology(topology); |
| |
| stateManager->setDrawShaders(&mQuad2DVS.getObj(), nullptr, &mDepthPS.getObj()); |
| |
| // Apply render target |
| stateManager->setRenderTarget(nullptr, dest.get()); |
| |
| // Set the viewport |
| stateManager->setSimpleViewport(destSize); |
| |
| // Apply texture and sampler |
| stateManager->setSimplePixelTextureAndSampler(source, mPointSampler); |
| |
| // Draw the quad |
| deviceContext->Draw(drawCount, 0); |
| |
| return angle::Result::Continue; |
| } |
| |
| angle::Result Blit11::copyDepthStencil(const gl::Context *context, |
| const TextureHelper11 &source, |
| unsigned int sourceSubresource, |
| const gl::Box &sourceArea, |
| const gl::Extents &sourceSize, |
| const TextureHelper11 &dest, |
| unsigned int destSubresource, |
| const gl::Box &destArea, |
| const gl::Extents &destSize, |
| const gl::Rectangle *scissor) |
| { |
| return copyDepthStencilImpl(context, source, sourceSubresource, sourceArea, sourceSize, dest, |
| destSubresource, destArea, destSize, scissor, false); |
| } |
| |
| angle::Result Blit11::copyDepthStencilImpl(const gl::Context *context, |
| const TextureHelper11 &source, |
| unsigned int sourceSubresource, |
| const gl::Box &sourceArea, |
| const gl::Extents &sourceSize, |
| const TextureHelper11 &dest, |
| unsigned int destSubresource, |
| const gl::Box &destArea, |
| const gl::Extents &destSize, |
| const gl::Rectangle *scissor, |
| bool stencilOnly) |
| { |
| auto srcDXGIFormat = source.getFormat(); |
| const auto &srcSizeInfo = d3d11::GetDXGIFormatSizeInfo(srcDXGIFormat); |
| unsigned int srcPixelSize = srcSizeInfo.pixelBytes; |
| unsigned int copyOffset = 0; |
| unsigned int copySize = srcPixelSize; |
| auto destDXGIFormat = dest.getFormat(); |
| const auto &destSizeInfo = d3d11::GetDXGIFormatSizeInfo(destDXGIFormat); |
| unsigned int destPixelSize = destSizeInfo.pixelBytes; |
| |
| ASSERT(srcDXGIFormat == destDXGIFormat || destDXGIFormat == DXGI_FORMAT_R32_TYPELESS); |
| |
| if (stencilOnly) |
| { |
| const auto &srcFormat = source.getFormatSet().format(); |
| |
| // Stencil channel should be right after the depth channel. Some views to depth/stencil |
| // resources have red channel for depth, in which case the depth channel bit width is in |
| // redBits. |
| ASSERT((srcFormat.redBits != 0) != (srcFormat.depthBits != 0)); |
| GLuint depthBits = srcFormat.redBits + srcFormat.depthBits; |
| // Known formats have either 24 or 32 bits of depth. |
| ASSERT(depthBits == 24 || depthBits == 32); |
| copyOffset = depthBits / 8; |
| |
| // Stencil is assumed to be 8-bit - currently this is true for all possible formats. |
| copySize = 1; |
| } |
| |
| if (srcDXGIFormat != destDXGIFormat) |
| { |
| if (srcDXGIFormat == DXGI_FORMAT_R24G8_TYPELESS) |
| { |
| ASSERT(sourceArea == destArea && sourceSize == destSize && scissor == nullptr); |
| return copyAndConvert(context, source, sourceSubresource, sourceArea, sourceSize, dest, |
| destSubresource, destArea, destSize, scissor, copyOffset, |
| copyOffset, copySize, srcPixelSize, destPixelSize, |
| BlitD24S8ToD32F); |
| } |
| ASSERT(srcDXGIFormat == DXGI_FORMAT_R32G8X24_TYPELESS); |
| return copyAndConvert(context, source, sourceSubresource, sourceArea, sourceSize, dest, |
| destSubresource, destArea, destSize, scissor, copyOffset, copyOffset, |
| copySize, srcPixelSize, destPixelSize, BlitD32FS8ToD32F); |
| } |
| |
| return copyAndConvert(context, source, sourceSubresource, sourceArea, sourceSize, dest, |
| destSubresource, destArea, destSize, scissor, copyOffset, copyOffset, |
| copySize, srcPixelSize, destPixelSize, StretchedBlitNearest); |
| } |
| |
| angle::Result Blit11::copyAndConvertImpl(const gl::Context *context, |
| const TextureHelper11 &source, |
| unsigned int sourceSubresource, |
| const gl::Box &sourceArea, |
| const gl::Extents &sourceSize, |
| const TextureHelper11 &destStaging, |
| const gl::Box &destArea, |
| const gl::Extents &destSize, |
| const gl::Rectangle *scissor, |
| size_t readOffset, |
| size_t writeOffset, |
| size_t copySize, |
| size_t srcPixelStride, |
| size_t destPixelStride, |
| BlitConvertFunction *convertFunction) |
| { |
| ANGLE_TRY(initResources(context)); |
| |
| ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); |
| |
| TextureHelper11 sourceStaging; |
| ANGLE_TRY(mRenderer->createStagingTexture(context, ResourceType::Texture2D, |
| source.getFormatSet(), sourceSize, |
| StagingAccess::READ, &sourceStaging)); |
| |
| deviceContext->CopySubresourceRegion(sourceStaging.get(), 0, 0, 0, 0, source.get(), |
| sourceSubresource, nullptr); |
| |
| D3D11_MAPPED_SUBRESOURCE sourceMapping; |
| ANGLE_TRY( |
| mRenderer->mapResource(context, sourceStaging.get(), 0, D3D11_MAP_READ, 0, &sourceMapping)); |
| |
| D3D11_MAPPED_SUBRESOURCE destMapping; |
| angle::Result error = |
| mRenderer->mapResource(context, destStaging.get(), 0, D3D11_MAP_WRITE, 0, &destMapping); |
| if (error == angle::Result::Stop) |
| { |
| deviceContext->Unmap(sourceStaging.get(), 0); |
| return error; |
| } |
| |
| // Clip dest area to the destination size |
| gl::Rectangle clipRect = gl::Rectangle(0, 0, destSize.width, destSize.height); |
| |
| // Clip dest area to the scissor |
| if (scissor) |
| { |
| if (!gl::ClipRectangle(clipRect, *scissor, &clipRect)) |
| { |
| return angle::Result::Continue; |
| } |
| } |
| |
| convertFunction(sourceArea, destArea, clipRect, sourceSize, sourceMapping.RowPitch, |
| destMapping.RowPitch, readOffset, writeOffset, copySize, srcPixelStride, |
| destPixelStride, static_cast<const uint8_t *>(sourceMapping.pData), |
| static_cast<uint8_t *>(destMapping.pData)); |
| |
| deviceContext->Unmap(sourceStaging.get(), 0); |
| deviceContext->Unmap(destStaging.get(), 0); |
| |
| return angle::Result::Continue; |
| } |
| |
| angle::Result Blit11::copyAndConvert(const gl::Context *context, |
| const TextureHelper11 &source, |
| unsigned int sourceSubresource, |
| const gl::Box &sourceArea, |
| const gl::Extents &sourceSize, |
| const TextureHelper11 &dest, |
| unsigned int destSubresource, |
| const gl::Box &destArea, |
| const gl::Extents &destSize, |
| const gl::Rectangle *scissor, |
| size_t readOffset, |
| size_t writeOffset, |
| size_t copySize, |
| size_t srcPixelStride, |
| size_t destPixelStride, |
| BlitConvertFunction *convertFunction) |
| { |
| ANGLE_TRY(initResources(context)); |
| |
| ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); |
| |
| // HACK: Create the destination staging buffer as a read/write texture so |
| // ID3D11DevicContext::UpdateSubresource can be called |
| // using it's mapped data as a source |
| TextureHelper11 destStaging; |
| ANGLE_TRY(mRenderer->createStagingTexture(context, ResourceType::Texture2D, dest.getFormatSet(), |
| destSize, StagingAccess::READ_WRITE, &destStaging)); |
| |
| deviceContext->CopySubresourceRegion(destStaging.get(), 0, 0, 0, 0, dest.get(), destSubresource, |
| nullptr); |
| |
| ANGLE_TRY(copyAndConvertImpl(context, source, sourceSubresource, sourceArea, sourceSize, |
| destStaging, destArea, destSize, scissor, readOffset, writeOffset, |
| copySize, srcPixelStride, destPixelStride, convertFunction)); |
| |
| // Work around timeouts/TDRs in older NVIDIA drivers. |
| if (mRenderer->getFeatures().depthStencilBlitExtraCopy.enabled) |
| { |
| D3D11_MAPPED_SUBRESOURCE mapped; |
| ANGLE_TRY( |
| mRenderer->mapResource(context, destStaging.get(), 0, D3D11_MAP_READ, 0, &mapped)); |
| deviceContext->UpdateSubresource(dest.get(), destSubresource, nullptr, mapped.pData, |
| mapped.RowPitch, mapped.DepthPitch); |
| deviceContext->Unmap(destStaging.get(), 0); |
| } |
| else |
| { |
| deviceContext->CopySubresourceRegion(dest.get(), destSubresource, 0, 0, 0, |
| destStaging.get(), 0, nullptr); |
| } |
| |
| return angle::Result::Continue; |
| } |
| |
| angle::Result Blit11::addBlitShaderToMap(const gl::Context *context, |
| BlitShaderType blitShaderType, |
| ShaderDimension dimension, |
| const ShaderData &shaderData, |
| const char *name) |
| { |
| ASSERT(mBlitShaderMap.find(blitShaderType) == mBlitShaderMap.end()); |
| |
| d3d11::PixelShader ps; |
| ANGLE_TRY(mRenderer->allocateResource(GetImplAs<Context11>(context), shaderData, &ps)); |
| ps.setDebugName(name); |
| |
| Shader shader; |
| shader.dimension = dimension; |
| shader.pixelShader = std::move(ps); |
| |
| mBlitShaderMap[blitShaderType] = std::move(shader); |
| return angle::Result::Continue; |
| } |
| |
| angle::Result Blit11::addSwizzleShaderToMap(const gl::Context *context, |
| SwizzleShaderType swizzleShaderType, |
| ShaderDimension dimension, |
| const ShaderData &shaderData, |
| const char *name) |
| { |
| ASSERT(mSwizzleShaderMap.find(swizzleShaderType) == mSwizzleShaderMap.end()); |
| |
| d3d11::PixelShader ps; |
| ANGLE_TRY(mRenderer->allocateResource(GetImplAs<Context11>(context), shaderData, &ps)); |
| ps.setDebugName(name); |
| |
| Shader shader; |
| shader.dimension = dimension; |
| shader.pixelShader = std::move(ps); |
| |
| mSwizzleShaderMap[swizzleShaderType] = std::move(shader); |
| return angle::Result::Continue; |
| } |
| |
| void Blit11::clearShaderMap() |
| { |
| mBlitShaderMap.clear(); |
| mSwizzleShaderMap.clear(); |
| } |
| |
| Blit11::BlitShaderOperation Blit11::getBlitShaderOperation(GLenum destinationFormat, |
| GLenum sourceFormat, |
| bool isSrcSigned, |
| bool isDestSigned, |
| bool unpackPremultiplyAlpha, |
| bool unpackUnmultiplyAlpha, |
| GLenum destTypeForDownsampling) |
| { |
| bool floatToIntBlit = |
| !gl::IsIntegerFormat(sourceFormat) && gl::IsIntegerFormat(destinationFormat); |
| |
| if (isSrcSigned) |
| { |
| ASSERT(!unpackPremultiplyAlpha && !unpackUnmultiplyAlpha); |
| switch (destinationFormat) |
| { |
| case GL_RGBA_INTEGER: |
| return RGBAI; |
| case GL_RGB_INTEGER: |
| return RGBI; |
| case GL_RG_INTEGER: |
| return RGI; |
| case GL_RED_INTEGER: |
| return RI; |
| default: |
| UNREACHABLE(); |
| return OPERATION_INVALID; |
| } |
| } |
| else if (isDestSigned) |
| { |
| ASSERT(floatToIntBlit); |
| |
| switch (destinationFormat) |
| { |
| case GL_RGBA_INTEGER: |
| if (unpackPremultiplyAlpha == unpackUnmultiplyAlpha) |
| { |
| return RGBAF_TOI; |
| } |
| else |
| { |
| return unpackPremultiplyAlpha ? RGBAF_TOI_PREMULTIPLY : RGBAF_TOI_UNMULTIPLY; |
| } |
| break; |
| case GL_RGB_INTEGER: |
| case GL_RG_INTEGER: |
| case GL_RED_INTEGER: |
| if (unpackPremultiplyAlpha == unpackUnmultiplyAlpha) |
| { |
| return RGBF_TOI; |
| } |
| else |
| { |
| return unpackPremultiplyAlpha ? RGBF_TOI_PREMULTIPLY : RGBF_TOI_UNMULTIPLY; |
| } |
| break; |
| default: |
| UNREACHABLE(); |
| return OPERATION_INVALID; |
| } |
| } |
| else |
| { |
| // Check for the downsample formats first |
| switch (destTypeForDownsampling) |
| { |
| case GL_UNSIGNED_SHORT_4_4_4_4: |
| ASSERT(destinationFormat == GL_RGBA && !floatToIntBlit); |
| if (unpackPremultiplyAlpha == unpackUnmultiplyAlpha) |
| { |
| return RGBAF_4444; |
| } |
| else if (unpackPremultiplyAlpha) |
| { |
| return RGBAF_4444_PREMULTIPLY; |
| } |
| else |
| { |
| return RGBAF_4444_UNMULTIPLY; |
| } |
| |
| case GL_UNSIGNED_SHORT_5_6_5: |
| ASSERT(destinationFormat == GL_RGB && !floatToIntBlit); |
| if (unpackPremultiplyAlpha == unpackUnmultiplyAlpha) |
| { |
| return RGBF_565; |
| } |
| else |
| { |
| return unpackPremultiplyAlpha ? RGBF_565_PREMULTIPLY : RGBF_565_UNMULTIPLY; |
| } |
| case GL_UNSIGNED_SHORT_5_5_5_1: |
| if (unpackPremultiplyAlpha == unpackUnmultiplyAlpha) |
| { |
| return RGBAF_5551; |
| } |
| else |
| { |
| return unpackPremultiplyAlpha ? RGBAF_5551_PREMULTIPLY : RGBAF_5551_UNMULTIPLY; |
| } |
| |
| default: |
| // By default, use the regular passthrough/multiply/unmultiply shaders. The above |
| // shaders are only needed for some emulated texture formats. |
| break; |
| } |
| |
| if (unpackPremultiplyAlpha != unpackUnmultiplyAlpha || floatToIntBlit) |
| { |
| switch (destinationFormat) |
| { |
| case GL_RGBA: |
| case GL_BGRA_EXT: |
| ASSERT(!floatToIntBlit); |
| return unpackPremultiplyAlpha ? RGBAF_PREMULTIPLY : RGBAF_UNMULTIPLY; |
| case GL_RGB: |
| case GL_RG: |
| case GL_RED: |
| if (unpackPremultiplyAlpha == unpackUnmultiplyAlpha) |
| { |
| return RGBF_TOUI; |
| } |
| else |
| { |
| return unpackPremultiplyAlpha ? RGBF_PREMULTIPLY : RGBF_UNMULTIPLY; |
| } |
| case GL_RGBA_INTEGER: |
| if (unpackPremultiplyAlpha == unpackUnmultiplyAlpha) |
| { |
| return RGBAF_TOUI; |
| } |
| else |
| { |
| return unpackPremultiplyAlpha ? RGBAF_TOUI_PREMULTIPLY |
| : RGBAF_TOUI_UNMULTIPLY; |
| } |
| case GL_RGB_INTEGER: |
| case GL_RG_INTEGER: |
| case GL_RED_INTEGER: |
| if (unpackPremultiplyAlpha == unpackUnmultiplyAlpha) |
| { |
| return RGBF_TOUI; |
| } |
| else |
| { |
| return unpackPremultiplyAlpha ? RGBF_TOUI_PREMULTIPLY |
| : RGBF_TOUI_UNMULTIPLY; |
| } |
| case GL_LUMINANCE: |
| ASSERT(!floatToIntBlit); |
| return unpackPremultiplyAlpha ? LUMAF_PREMULTIPLY : LUMAF_UNMULTIPLY; |
| |
| case GL_LUMINANCE_ALPHA: |
| ASSERT(!floatToIntBlit); |
| return unpackPremultiplyAlpha ? LUMAALPHAF_PREMULTIPLY : LUMAALPHAF_UNMULTIPLY; |
| case GL_ALPHA: |
| return ALPHA; |
| default: |
| UNREACHABLE(); |
| return OPERATION_INVALID; |
| } |
| } |
| else |
| { |
| switch (destinationFormat) |
| { |
| case GL_RGBA: |
| return RGBAF; |
| case GL_RGBA_INTEGER: |
| return RGBAUI; |
| case GL_BGRA_EXT: |
| return BGRAF; |
| case GL_RGB: |
| return RGBF; |
| case GL_RGB_INTEGER: |
| return RGBUI; |
| case GL_RG: |
| return RGF; |
| case GL_RG_INTEGER: |
| return RGUI; |
| case GL_RED: |
| return RF; |
| case GL_RED_INTEGER: |
| return RUI; |
| case GL_ALPHA: |
| return ALPHA; |
| case GL_LUMINANCE: |
| return LUMA; |
| case GL_LUMINANCE_ALPHA: |
| return LUMAALPHA; |
| default: |
| UNREACHABLE(); |
| return OPERATION_INVALID; |
| } |
| } |
| } |
| } |
| |
| angle::Result Blit11::getBlitShader(const gl::Context *context, |
| GLenum destFormat, |
| GLenum sourceFormat, |
| bool isSrcSigned, |
| bool isDestSigned, |
| bool unpackPremultiplyAlpha, |
| bool unpackUnmultiplyAlpha, |
| GLenum destTypeForDownsampling, |
| ShaderDimension dimension, |
| const Shader **shader) |
| { |
| BlitShaderOperation blitShaderOperation = OPERATION_INVALID; |
| |
| blitShaderOperation = getBlitShaderOperation(destFormat, sourceFormat, isSrcSigned, |
| isDestSigned, unpackPremultiplyAlpha, |
| unpackUnmultiplyAlpha, destTypeForDownsampling); |
| |
| BlitShaderType blitShaderType = BLITSHADER_INVALID; |
| |
| blitShaderType = getBlitShaderType(blitShaderOperation, dimension); |
| |
| ANGLE_CHECK_HR(GetImplAs<Context11>(context), blitShaderType != BLITSHADER_INVALID, |
| "Internal blit shader type mismatch", E_FAIL); |
| |
| auto blitShaderIt = mBlitShaderMap.find(blitShaderType); |
| if (blitShaderIt != mBlitShaderMap.end()) |
| { |
| *shader = &blitShaderIt->second; |
| return angle::Result::Continue; |
| } |
| |
| ASSERT(dimension == SHADER_2D || mRenderer->isES3Capable()); |
| |
| ANGLE_TRY(mapBlitShader(context, blitShaderType)); |
| |
| blitShaderIt = mBlitShaderMap.find(blitShaderType); |
| ASSERT(blitShaderIt != mBlitShaderMap.end()); |
| *shader = &blitShaderIt->second; |
| return angle::Result::Continue; |
| } |
| |
| angle::Result Blit11::getSwizzleShader(const gl::Context *context, |
| GLenum type, |
| D3D11_SRV_DIMENSION viewDimension, |
| const Shader **shader) |
| { |
| SwizzleShaderType swizzleShaderType = GetSwizzleShaderType(type, viewDimension); |
| |
| ANGLE_CHECK_HR(GetImplAs<Context11>(context), swizzleShaderType != SWIZZLESHADER_INVALID, |
| "Swizzle shader type not found", E_FAIL); |
| |
| auto swizzleShaderIt = mSwizzleShaderMap.find(swizzleShaderType); |
| if (swizzleShaderIt != mSwizzleShaderMap.end()) |
| { |
| *shader = &swizzleShaderIt->second; |
| return angle::Result::Continue; |
| } |
| |
| // Swizzling shaders (OpenGL ES 3+) |
| ASSERT(mRenderer->isES3Capable()); |
| |
| switch (swizzleShaderType) |
| { |
| case SWIZZLESHADER_2D_FLOAT: |
| ANGLE_TRY(addSwizzleShaderToMap(context, swizzleShaderType, SHADER_2D, |
| ShaderData(g_PS_SwizzleF2D), |
| "Blit11 2D F swizzle pixel shader")); |
| break; |
| case SWIZZLESHADER_2D_UINT: |
| ANGLE_TRY(addSwizzleShaderToMap(context, swizzleShaderType, SHADER_2D, |
| ShaderData(g_PS_SwizzleUI2D), |
| "Blit11 2D UI swizzle pixel shader")); |
| break; |
| case SWIZZLESHADER_2D_INT: |
| ANGLE_TRY(addSwizzleShaderToMap(context, swizzleShaderType, SHADER_2D, |
| ShaderData(g_PS_SwizzleI2D), |
| "Blit11 2D I swizzle pixel shader")); |
| break; |
| case SWIZZLESHADER_CUBE_FLOAT: |
| ANGLE_TRY(addSwizzleShaderToMap(context, swizzleShaderType, SHADER_3D, |
| ShaderData(g_PS_SwizzleF2DArray), |
| "Blit11 2D Cube F swizzle pixel shader")); |
| break; |
| case SWIZZLESHADER_CUBE_UINT: |
| ANGLE_TRY(addSwizzleShaderToMap(context, swizzleShaderType, SHADER_3D, |
| ShaderData(g_PS_SwizzleUI2DArray), |
| "Blit11 2D Cube UI swizzle pixel shader")); |
| break; |
| case SWIZZLESHADER_CUBE_INT: |
| ANGLE_TRY(addSwizzleShaderToMap(context, swizzleShaderType, SHADER_3D, |
| ShaderData(g_PS_SwizzleI2DArray), |
| "Blit11 2D Cube I swizzle pixel shader")); |
| break; |
| case SWIZZLESHADER_3D_FLOAT: |
| ANGLE_TRY(addSwizzleShaderToMap(context, swizzleShaderType, SHADER_3D, |
| ShaderData(g_PS_SwizzleF3D), |
| "Blit11 3D F swizzle pixel shader")); |
| break; |
| case SWIZZLESHADER_3D_UINT: |
| ANGLE_TRY(addSwizzleShaderToMap(context, swizzleShaderType, SHADER_3D, |
| ShaderData(g_PS_SwizzleUI3D), |
| "Blit11 3D UI swizzle pixel shader")); |
| break; |
| case SWIZZLESHADER_3D_INT: |
| ANGLE_TRY(addSwizzleShaderToMap(context, swizzleShaderType, SHADER_3D, |
| ShaderData(g_PS_SwizzleI3D), |
| "Blit11 3D I swizzle pixel shader")); |
| break; |
| case SWIZZLESHADER_ARRAY_FLOAT: |
| ANGLE_TRY(addSwizzleShaderToMap(context, swizzleShaderType, SHADER_3D, |
| ShaderData(g_PS_SwizzleF2DArray), |
| "Blit11 2D Array F swizzle pixel shader")); |
| break; |
| case SWIZZLESHADER_ARRAY_UINT: |
| ANGLE_TRY(addSwizzleShaderToMap(context, swizzleShaderType, SHADER_3D, |
| ShaderData(g_PS_SwizzleUI2DArray), |
| "Blit11 2D Array UI swizzle pixel shader")); |
| break; |
| case SWIZZLESHADER_ARRAY_INT: |
| ANGLE_TRY(addSwizzleShaderToMap(context, swizzleShaderType, SHADER_3D, |
| ShaderData(g_PS_SwizzleI2DArray), |
| "Blit11 2D Array I swizzle pixel shader")); |
| break; |
| default: |
| ANGLE_HR_UNREACHABLE(GetImplAs<Context11>(context)); |
| } |
| |
| swizzleShaderIt = mSwizzleShaderMap.find(swizzleShaderType); |
| ASSERT(swizzleShaderIt != mSwizzleShaderMap.end()); |
| *shader = &swizzleShaderIt->second; |
| return angle::Result::Continue; |
| } |
| |
| angle::Result Blit11::resolveDepth(const gl::Context *context, |
| RenderTarget11 *depth, |
| TextureHelper11 *textureOut) |
| { |
| ANGLE_TRY(initResources(context)); |
| |
| // Multisampled depth stencil SRVs are not available in feature level 10.0 |
| ASSERT(mRenderer->getRenderer11DeviceCaps().featureLevel > D3D_FEATURE_LEVEL_10_0); |
| |
| const auto &extents = depth->getExtents(); |
| auto *deviceContext = mRenderer->getDeviceContext(); |
| auto *stateManager = mRenderer->getStateManager(); |
| |
| ANGLE_TRY(initResolveDepthOnly(context, depth->getFormatSet(), extents)); |
| |
| Context11 *context11 = GetImplAs<Context11>(context); |
| |
| ANGLE_TRY(mResolveDepthStencilVS.resolve(context11, mRenderer)); |
| ANGLE_TRY(mResolveDepthPS.resolve(context11, mRenderer)); |
| |
| // Apply the necessary state changes to the D3D11 immediate device context. |
| stateManager->setInputLayout(nullptr); |
| stateManager->setPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); |
| stateManager->setDrawShaders(&mResolveDepthStencilVS.getObj(), nullptr, |
| &mResolveDepthPS.getObj()); |
| stateManager->setRasterizerState(nullptr); |
| stateManager->setDepthStencilState(&mDepthStencilState, 0xFFFFFFFF); |
| stateManager->setRenderTargets(nullptr, 0, mResolvedDepthDSView.get()); |
| stateManager->setSimpleBlendState(nullptr); |
| stateManager->setSimpleViewport(extents); |
| |
| // Set the viewport |
| stateManager->setShaderResourceShared(gl::ShaderType::Fragment, 0, |
| &depth->getShaderResourceView(context)); |
| |
| // Trigger the blit on the GPU. |
| deviceContext->Draw(6, 0); |
| |
| *textureOut = mResolvedDepth; |
| return angle::Result::Continue; |
| } |
| |
| angle::Result Blit11::initResolveDepthOnly(const gl::Context *context, |
| const d3d11::Format &format, |
| const gl::Extents &extents) |
| { |
| if (mResolvedDepth.valid() && extents == mResolvedDepth.getExtents() && |
| format.texFormat == mResolvedDepth.getFormat()) |
| { |
| return angle::Result::Continue; |
| } |
| |
| D3D11_TEXTURE2D_DESC textureDesc; |
| textureDesc.Width = extents.width; |
| textureDesc.Height = extents.height; |
| textureDesc.MipLevels = 1; |
| textureDesc.ArraySize = 1; |
| textureDesc.Format = format.texFormat; |
| textureDesc.SampleDesc.Count = 1; |
| textureDesc.SampleDesc.Quality = 0; |
| textureDesc.Usage = D3D11_USAGE_DEFAULT; |
| textureDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE; |
| textureDesc.CPUAccessFlags = 0; |
| textureDesc.MiscFlags = 0; |
| |
| Context11 *context11 = GetImplAs<Context11>(context); |
| |
| ANGLE_TRY(mRenderer->allocateTexture(context11, textureDesc, format, &mResolvedDepth)); |
| mResolvedDepth.setDebugName("Blit11::mResolvedDepth"); |
| |
| D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; |
| dsvDesc.Flags = 0; |
| dsvDesc.Format = format.dsvFormat; |
| dsvDesc.Texture2D.MipSlice = 0; |
| dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; |
| |
| ANGLE_TRY(mRenderer->allocateResource(context11, dsvDesc, mResolvedDepth.get(), |
| &mResolvedDepthDSView)); |
| mResolvedDepthDSView.setDebugName("Blit11::mResolvedDepthDSView"); |
| |
| // Possibly D3D11 bug or undefined behaviour: Clear the DSV so that our first render |
| // works as expected. Otherwise the results of the first use seem to be incorrect. |
| ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); |
| deviceContext->ClearDepthStencilView(mResolvedDepthDSView.get(), D3D11_CLEAR_DEPTH, 1.0f, 0); |
| |
| return angle::Result::Continue; |
| } |
| |
| angle::Result Blit11::initResolveDepthStencil(const gl::Context *context, |
| const gl::Extents &extents) |
| { |
| // Check if we need to recreate depth stencil view |
| if (mResolvedDepthStencil.valid() && extents == mResolvedDepthStencil.getExtents()) |
| { |
| ASSERT(mResolvedDepthStencil.getFormat() == DXGI_FORMAT_R32G32_FLOAT); |
| return angle::Result::Continue; |
| } |
| |
| if (mResolvedDepthStencil.valid()) |
| { |
| releaseResolveDepthStencilResources(); |
| } |
| |
| const auto &formatSet = d3d11::Format::Get(GL_RG32F, mRenderer->getRenderer11DeviceCaps()); |
| |
| D3D11_TEXTURE2D_DESC textureDesc; |
| textureDesc.Width = extents.width; |
| textureDesc.Height = extents.height; |
| textureDesc.MipLevels = 1; |
| textureDesc.ArraySize = 1; |
| textureDesc.Format = formatSet.texFormat; |
| textureDesc.SampleDesc.Count = 1; |
| textureDesc.SampleDesc.Quality = 0; |
| textureDesc.Usage = D3D11_USAGE_DEFAULT; |
| textureDesc.BindFlags = D3D11_BIND_RENDER_TARGET; |
| textureDesc.CPUAccessFlags = 0; |
| textureDesc.MiscFlags = 0; |
| |
| Context11 *context11 = GetImplAs<Context11>(context); |
| |
| ANGLE_TRY( |
| mRenderer->allocateTexture(context11, textureDesc, formatSet, &mResolvedDepthStencil)); |
| mResolvedDepthStencil.setDebugName("Blit11::mResolvedDepthStencil"); |
| |
| ANGLE_TRY(mRenderer->allocateResourceNoDesc(context11, mResolvedDepthStencil.get(), |
| &mResolvedDepthStencilRTView)); |
| mResolvedDepthStencilRTView.setDebugName("Blit11::mResolvedDepthStencilRTView"); |
| |
| return angle::Result::Continue; |
| } |
| |
| angle::Result Blit11::resolveStencil(const gl::Context *context, |
| RenderTarget11 *depthStencil, |
| bool alsoDepth, |
| TextureHelper11 *textureOut) |
| { |
| ANGLE_TRY(initResources(context)); |
| |
| // Multisampled depth stencil SRVs are not available in feature level 10.0 |
| ASSERT(mRenderer->getRenderer11DeviceCaps().featureLevel > D3D_FEATURE_LEVEL_10_0); |
| |
| const auto &extents = depthStencil->getExtents(); |
| |
| ANGLE_TRY(initResolveDepthStencil(context, extents)); |
| |
| ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); |
| auto *stateManager = mRenderer->getStateManager(); |
| ID3D11Resource *stencilResource = depthStencil->getTexture().get(); |
| |
| // Check if we need to re-create the stencil SRV. |
| if (mStencilSRV.valid()) |
| { |
| ID3D11Resource *priorResource = nullptr; |
| mStencilSRV.get()->GetResource(&priorResource); |
| |
| if (stencilResource != priorResource) |
| { |
| mStencilSRV.reset(); |
| } |
| |
| SafeRelease(priorResource); |
| } |
| |
| Context11 *context11 = GetImplAs<Context11>(context); |
| |
| if (!mStencilSRV.valid()) |
| { |
| D3D11_SHADER_RESOURCE_VIEW_DESC srViewDesc; |
| srViewDesc.Format = GetStencilSRVFormat(depthStencil->getFormatSet()); |
| srViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS; |
| |
| ANGLE_TRY( |
| mRenderer->allocateResource(context11, srViewDesc, stencilResource, &mStencilSRV)); |
| mStencilSRV.setDebugName("Blit11::mStencilSRV"); |
| } |
| |
| // Notify the Renderer that all state should be invalidated. |
| ANGLE_TRY(mResolveDepthStencilVS.resolve(context11, mRenderer)); |
| |
| // Resolving the depth buffer works by sampling the depth in the shader using a SRV, then |
| // writing to the resolved depth buffer using SV_Depth. We can't use this method for stencil |
| // because SV_StencilRef isn't supported until HLSL 5.1/D3D11.3. |
| const d3d11::PixelShader *pixelShader = nullptr; |
| if (alsoDepth) |
| { |
| ANGLE_TRY(mResolveDepthStencilPS.resolve(context11, mRenderer)); |
| pixelShader = &mResolveDepthStencilPS.getObj(); |
| } |
| else |
| { |
| ANGLE_TRY(mResolveStencilPS.resolve(context11, mRenderer)); |
| pixelShader = &mResolveStencilPS.getObj(); |
| } |
| |
| // Apply the necessary state changes to the D3D11 immediate device context. |
| stateManager->setInputLayout(nullptr); |
| stateManager->setPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); |
| stateManager->setDrawShaders(&mResolveDepthStencilVS.getObj(), nullptr, pixelShader); |
| stateManager->setRasterizerState(nullptr); |
| stateManager->setDepthStencilState(nullptr, 0xFFFFFFFF); |
| stateManager->setRenderTarget(mResolvedDepthStencilRTView.get(), nullptr); |
| stateManager->setSimpleBlendState(nullptr); |
| |
| // Set the viewport |
| stateManager->setSimpleViewport(extents); |
| stateManager->setShaderResourceShared(gl::ShaderType::Fragment, 0, |
| &depthStencil->getShaderResourceView(context)); |
| stateManager->setShaderResource(gl::ShaderType::Fragment, 1, &mStencilSRV); |
| |
| // Trigger the blit on the GPU. |
| deviceContext->Draw(6, 0); |
| |
| gl::Box copyBox(0, 0, 0, extents.width, extents.height, 1); |
| |
| ANGLE_TRY(mRenderer->createStagingTexture(context, ResourceType::Texture2D, |
| depthStencil->getFormatSet(), extents, |
| StagingAccess::READ_WRITE, textureOut)); |
| |
| const auto ©Function = GetCopyDepthStencilFunction(depthStencil->getInternalFormat()); |
| const auto &dsFormatSet = depthStencil->getFormatSet(); |
| const auto &dsDxgiInfo = d3d11::GetDXGIFormatSizeInfo(dsFormatSet.texFormat); |
| |
| ANGLE_TRY(copyAndConvertImpl(context, mResolvedDepthStencil, 0, copyBox, extents, *textureOut, |
| copyBox, extents, nullptr, 0, 0, 0, 8u, dsDxgiInfo.pixelBytes, |
| copyFunction)); |
| |
| return angle::Result::Continue; |
| } |
| |
| void Blit11::releaseResolveDepthStencilResources() |
| { |
| mStencilSRV.reset(); |
| mResolvedDepthStencilRTView.reset(); |
| } |
| |
| } // namespace rx |