blob: 2e9395cc57fc7040609da1d71648cf7df8527ba4 [file] [log] [blame]
//
// Copyright (c) 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 "libANGLE/formatutils.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
#include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h"
#include "third_party/trace_event/trace_event.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/passthroughlum2d11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughlumalpha2d11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr2d11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr2di11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr2dui11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg2d11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg2di11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg2dui11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2d11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2di11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2dui11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2d11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2di11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dui11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgbapremultiply2d11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgbaunmultiply2d11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgbpremultiply2d11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgbunmultiply2d11ps.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/passthroughlum3d11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughlumalpha3d11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr3d11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr3di11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr3dui11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg3d11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg3di11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg3dui11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3d11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3di11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3dui11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3d11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3di11ps.h"
#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3dui11ps.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
Blit11::Blit11(Renderer11 *renderer)
: mRenderer(renderer),
mResourcesInitialized(false),
mVertexBuffer(nullptr),
mPointSampler(nullptr),
mLinearSampler(nullptr),
mScissorEnabledRasterizerState(nullptr),
mScissorDisabledRasterizerState(nullptr),
mDepthStencilState(nullptr),
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(nullptr),
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(nullptr),
mResolvedDepthStencilRTView()
{
}
Blit11::~Blit11()
{
mQuad2DIL.release();
mQuad2DVS.release();
mDepthPS.release();
mQuad3DIL.release();
mQuad3DVS.release();
mQuad3DGS.release();
clearShaderMap();
releaseResolveDepthStencilResources();
}
gl::Error Blit11::initResources()
{
if (mResourcesInitialized)
{
return gl::NoError();
}
TRACE_EVENT0("gpu.angle", "Blit11::initResources");
HRESULT result;
ID3D11Device *device = mRenderer->getDevice();
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;
result = device->CreateBuffer(&vbDesc, nullptr, mVertexBuffer.GetAddressOf());
ASSERT(SUCCEEDED(result));
if (FAILED(result))
{
return gl::OutOfMemory() << "Failed to create blit vertex buffer, " << result;
}
d3d11::SetDebugName(mVertexBuffer, "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;
result = device->CreateSamplerState(&pointSamplerDesc, mPointSampler.GetAddressOf());
ASSERT(SUCCEEDED(result));
if (FAILED(result))
{
return gl::OutOfMemory() << "Failed to create blit point sampler state, " << result;
}
d3d11::SetDebugName(mPointSampler, "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;
result = device->CreateSamplerState(&linearSamplerDesc, mLinearSampler.GetAddressOf());
ASSERT(SUCCEEDED(result));
if (FAILED(result))
{
return gl::OutOfMemory() << "Failed to create blit linear sampler state, " << result;
}
d3d11::SetDebugName(mLinearSampler, "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;
result =
device->CreateRasterizerState(&rasterDesc, mScissorEnabledRasterizerState.GetAddressOf());
ASSERT(SUCCEEDED(result));
if (FAILED(result))
{
return gl::OutOfMemory() << "Failed to create blit scissoring rasterizer state, " << result;
}
d3d11::SetDebugName(mScissorEnabledRasterizerState, "Blit11 scissoring rasterizer state");
rasterDesc.ScissorEnable = FALSE;
result =
device->CreateRasterizerState(&rasterDesc, mScissorDisabledRasterizerState.GetAddressOf());
ASSERT(SUCCEEDED(result));
if (FAILED(result))
{
return gl::OutOfMemory() << "Failed to create blit no scissoring rasterizer state, "
<< result;
}
d3d11::SetDebugName(mScissorDisabledRasterizerState, "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;
result = device->CreateDepthStencilState(&depthStencilDesc, mDepthStencilState.GetAddressOf());
ASSERT(SUCCEEDED(result));
if (FAILED(result))
{
return gl::OutOfMemory() << "Failed to create blit depth stencil state, " << result;
}
d3d11::SetDebugName(mDepthStencilState, "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;
result = device->CreateBuffer(&swizzleBufferDesc, nullptr, mSwizzleCB.GetAddressOf());
ASSERT(SUCCEEDED(result));
if (FAILED(result))
{
return gl::OutOfMemory() << "Failed to create blit swizzle buffer, " << result;
}
d3d11::SetDebugName(mSwizzleCB, "Blit11 swizzle constant buffer");
mResourcesInitialized = true;
return gl::NoError();
}
// static
Blit11::BlitShaderType Blit11::GetBlitShaderType(GLenum destinationFormat,
bool isSigned,
bool unpackPremultiplyAlpha,
bool unpackUnmultiplyAlpha,
ShaderDimension dimension)
{
if (dimension == SHADER_3D)
{
ASSERT(!unpackPremultiplyAlpha && !unpackUnmultiplyAlpha);
if (isSigned)
{
switch (destinationFormat)
{
case GL_RGBA_INTEGER:
return BLITSHADER_3D_RGBAI;
case GL_RGB_INTEGER:
return BLITSHADER_3D_RGBI;
case GL_RG_INTEGER:
return BLITSHADER_3D_RGI;
case GL_RED_INTEGER:
return BLITSHADER_3D_RI;
default:
UNREACHABLE();
return BLITSHADER_INVALID;
}
}
else
{
switch (destinationFormat)
{
case GL_RGBA:
return BLITSHADER_3D_RGBAF;
case GL_RGBA_INTEGER:
return BLITSHADER_3D_RGBAUI;
case GL_BGRA_EXT:
return BLITSHADER_3D_BGRAF;
case GL_RGB:
return BLITSHADER_3D_RGBF;
case GL_RGB_INTEGER:
return BLITSHADER_3D_RGBUI;
case GL_RG:
return BLITSHADER_3D_RGF;
case GL_RG_INTEGER:
return BLITSHADER_3D_RGUI;
case GL_RED:
return BLITSHADER_3D_RF;
case GL_RED_INTEGER:
return BLITSHADER_3D_RUI;
case GL_ALPHA:
return BLITSHADER_3D_ALPHA;
case GL_LUMINANCE:
return BLITSHADER_3D_LUMA;
case GL_LUMINANCE_ALPHA:
return BLITSHADER_3D_LUMAALPHA;
default:
UNREACHABLE();
return BLITSHADER_INVALID;
}
}
}
else if (isSigned)
{
ASSERT(!unpackPremultiplyAlpha && !unpackUnmultiplyAlpha);
switch (destinationFormat)
{
case GL_RGBA_INTEGER:
return BLITSHADER_2D_RGBAI;
case GL_RGB_INTEGER:
return BLITSHADER_2D_RGBI;
case GL_RG_INTEGER:
return BLITSHADER_2D_RGI;
case GL_RED_INTEGER:
return BLITSHADER_2D_RI;
default:
UNREACHABLE();
return BLITSHADER_INVALID;
}
}
else
{
if (unpackPremultiplyAlpha != unpackUnmultiplyAlpha)
{
switch (destinationFormat)
{
case GL_RGBA:
return unpackPremultiplyAlpha ? BLITSHADER_2D_RGBAF_PREMULTIPLY
: BLITSHADER_2D_RGBAF_UNMULTIPLY;
case GL_BGRA_EXT:
return unpackPremultiplyAlpha ? BLITSHADER_2D_BGRAF_PREMULTIPLY
: BLITSHADER_2D_BGRAF_UNMULTIPLY;
case GL_RGB:
return unpackPremultiplyAlpha ? BLITSHADER_2D_RGBF_PREMULTIPLY
: BLITSHADER_2D_RGBF_UNMULTIPLY;
default:
UNREACHABLE();
return BLITSHADER_INVALID;
}
}
else
{
switch (destinationFormat)
{
case GL_RGBA:
return BLITSHADER_2D_RGBAF;
case GL_RGBA_INTEGER:
return BLITSHADER_2D_RGBAUI;
case GL_BGRA_EXT:
return BLITSHADER_2D_BGRAF;
case GL_RGB:
return BLITSHADER_2D_RGBF;
case GL_RGB_INTEGER:
return BLITSHADER_2D_RGBUI;
case GL_RG:
return BLITSHADER_2D_RGF;
case GL_RG_INTEGER:
return BLITSHADER_2D_RGUI;
case GL_RED:
return BLITSHADER_2D_RF;
case GL_RED_INTEGER:
return BLITSHADER_2D_RUI;
case GL_ALPHA:
return BLITSHADER_2D_ALPHA;
case GL_LUMINANCE:
return BLITSHADER_2D_LUMA;
case GL_LUMINANCE_ALPHA:
return BLITSHADER_2D_LUMAALPHA;
default:
UNREACHABLE();
return BLITSHADER_INVALID;
}
}
}
}
// 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;
}
}
Blit11::ShaderSupport Blit11::getShaderSupport(const Shader &shader)
{
ID3D11Device *device = mRenderer->getDevice();
ShaderSupport support;
if (shader.dimension == SHADER_2D)
{
support.inputLayout = mQuad2DIL.resolve(device);
support.vertexShader = mQuad2DVS.resolve(device);
support.geometryShader = nullptr;
support.vertexWriteFunction = Write2DVertices;
}
else
{
ASSERT(shader.dimension == SHADER_3D);
support.inputLayout = mQuad3DIL.resolve(device);
support.vertexShader = mQuad3DVS.resolve(device);
support.geometryShader = mQuad3DGS.resolve(device);
support.vertexWriteFunction = Write3DVertices;
}
return support;
}
gl::Error Blit11::swizzleTexture(ID3D11ShaderResourceView *source,
const d3d11::RenderTargetView &dest,
const gl::Extents &size,
const gl::SwizzleState &swizzleTarget)
{
ANGLE_TRY(initResources());
HRESULT result;
ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
D3D11_SHADER_RESOURCE_VIEW_DESC sourceSRVDesc;
source->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(shaderType, sourceSRVDesc.ViewDimension, &shader));
// Set vertices
D3D11_MAPPED_SUBRESOURCE mappedResource;
result =
deviceContext->Map(mVertexBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
if (FAILED(result))
{
return gl::OutOfMemory() << "Failed to map internal vertex buffer for swizzle, " << result;
}
const ShaderSupport &support = getShaderSupport(*shader);
UINT stride = 0;
UINT startIdx = 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
result = deviceContext->Map(mSwizzleCB.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
if (FAILED(result))
{
return gl::OutOfMemory() << "Failed to map internal constant buffer for swizzle, "
<< result;
}
unsigned int *swizzleIndices = reinterpret_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);
// Apply vertex buffer
deviceContext->IASetVertexBuffers(0, 1, mVertexBuffer.GetAddressOf(), &stride, &startIdx);
// Apply constant buffer
deviceContext->PSSetConstantBuffers(0, 1, mSwizzleCB.GetAddressOf());
// Apply state
deviceContext->OMSetBlendState(nullptr, nullptr, 0xFFFFFFF);
deviceContext->OMSetDepthStencilState(nullptr, 0xFFFFFFFF);
deviceContext->RSSetState(mScissorDisabledRasterizerState.Get());
// Apply shaders
deviceContext->IASetInputLayout(support.inputLayout);
deviceContext->IASetPrimitiveTopology(topology);
deviceContext->VSSetShader(support.vertexShader, nullptr, 0);
deviceContext->PSSetShader(shader->pixelShader, nullptr, 0);
deviceContext->GSSetShader(support.geometryShader, nullptr, 0);
// Unset the currently bound shader resource to avoid conflicts
auto stateManager = mRenderer->getStateManager();
stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, nullptr);
// Apply render target
stateManager->setOneTimeRenderTarget(dest.get(), nullptr);
// Set the viewport
D3D11_VIEWPORT viewport;
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = static_cast<FLOAT>(size.width);
viewport.Height = static_cast<FLOAT>(size.height);
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
deviceContext->RSSetViewports(1, &viewport);
// Apply textures
stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, source);
// Apply samplers
deviceContext->PSSetSamplers(0, 1, mPointSampler.GetAddressOf());
// Draw the quad
deviceContext->Draw(drawCount, 0);
// Unbind textures and render targets and vertex buffer
stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, nullptr);
UINT zero = 0;
ID3D11Buffer *const nullBuffer = nullptr;
deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero);
mRenderer->markAllStateDirty();
return gl::NoError();
}
gl::Error Blit11::copyTexture(ID3D11ShaderResourceView *source,
const gl::Box &sourceArea,
const gl::Extents &sourceSize,
const d3d11::RenderTargetView &dest,
const gl::Box &destArea,
const gl::Extents &destSize,
const gl::Rectangle *scissor,
GLenum destFormat,
GLenum filter,
bool maskOffAlpha,
bool unpackPremultiplyAlpha,
bool unpackUnmultiplyAlpha)
{
ANGLE_TRY(initResources());
HRESULT result;
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->GetDesc(&sourceSRVDesc);
GLenum componentType = d3d11::GetComponentType(sourceSRVDesc.Format);
ASSERT(componentType != GL_NONE);
ASSERT(componentType != GL_SIGNED_NORMALIZED);
bool isSigned = (componentType == GL_INT);
ShaderDimension dimension =
(sourceSRVDesc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE3D) ? SHADER_3D : SHADER_2D;
const Shader *shader = nullptr;
ANGLE_TRY(getBlitShader(destFormat, isSigned, unpackPremultiplyAlpha, unpackUnmultiplyAlpha,
dimension, &shader));
const ShaderSupport &support = getShaderSupport(*shader);
// Set vertices
D3D11_MAPPED_SUBRESOURCE mappedResource;
result =
deviceContext->Map(mVertexBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
if (FAILED(result))
{
return gl::OutOfMemory() << "Failed to map internal vertex buffer for texture copy, "
<< result;
}
UINT stride = 0;
UINT startIdx = 0;
UINT drawCount = 0;
D3D11_PRIMITIVE_TOPOLOGY topology;
support.vertexWriteFunction(sourceArea, sourceSize, destArea, destSize, mappedResource.pData,
&stride, &drawCount, &topology);
deviceContext->Unmap(mVertexBuffer.Get(), 0);
// Apply vertex buffer
deviceContext->IASetVertexBuffers(0, 1, mVertexBuffer.GetAddressOf(), &stride, &startIdx);
// Apply state
if (maskOffAlpha)
{
ID3D11BlendState *blendState = mAlphaMaskBlendState.resolve(mRenderer->getDevice());
ASSERT(blendState);
deviceContext->OMSetBlendState(blendState, nullptr, 0xFFFFFFF);
}
else
{
deviceContext->OMSetBlendState(nullptr, nullptr, 0xFFFFFFF);
}
deviceContext->OMSetDepthStencilState(nullptr, 0xFFFFFFFF);
if (scissor)
{
D3D11_RECT scissorRect;
scissorRect.left = scissor->x;
scissorRect.right = scissor->x + scissor->width;
scissorRect.top = scissor->y;
scissorRect.bottom = scissor->y + scissor->height;
deviceContext->RSSetScissorRects(1, &scissorRect);
deviceContext->RSSetState(mScissorEnabledRasterizerState.Get());
}
else
{
deviceContext->RSSetState(mScissorDisabledRasterizerState.Get());
}
// Apply shaders
deviceContext->IASetInputLayout(support.inputLayout);
deviceContext->IASetPrimitiveTopology(topology);
deviceContext->VSSetShader(support.vertexShader, nullptr, 0);
deviceContext->PSSetShader(shader->pixelShader, nullptr, 0);
deviceContext->GSSetShader(support.geometryShader, nullptr, 0);
// Unset the currently bound shader resource to avoid conflicts
auto stateManager = mRenderer->getStateManager();
stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, nullptr);
// Apply render target
stateManager->setOneTimeRenderTarget(dest.get(), nullptr);
// Set the viewport
D3D11_VIEWPORT viewport;
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = static_cast<FLOAT>(destSize.width);
viewport.Height = static_cast<FLOAT>(destSize.height);
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
deviceContext->RSSetViewports(1, &viewport);
// Apply textures
stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, source);
// Apply samplers
ID3D11SamplerState *sampler = nullptr;
switch (filter)
{
case GL_NEAREST:
sampler = mPointSampler.Get();
break;
case GL_LINEAR:
sampler = mLinearSampler.Get();
break;
default:
UNREACHABLE();
return gl::InternalError() << "Internal error, unknown blit filter mode.";
}
deviceContext->PSSetSamplers(0, 1, &sampler);
// Draw the quad
deviceContext->Draw(drawCount, 0);
// Unbind textures and render targets and vertex buffer
stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, nullptr);
UINT zero = 0;
ID3D11Buffer *const nullBuffer = nullptr;
deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero);
mRenderer->markAllStateDirty();
return gl::NoError();
}
gl::Error Blit11::copyStencil(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(source, sourceSubresource, sourceArea, sourceSize, dest,
destSubresource, destArea, destSize, scissor, true);
}
gl::Error Blit11::copyDepth(ID3D11ShaderResourceView *source,
const gl::Box &sourceArea,
const gl::Extents &sourceSize,
ID3D11DepthStencilView *dest,
const gl::Box &destArea,
const gl::Extents &destSize,
const gl::Rectangle *scissor)
{
ANGLE_TRY(initResources());
HRESULT result;
ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
// Set vertices
D3D11_MAPPED_SUBRESOURCE mappedResource;
result =
deviceContext->Map(mVertexBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
if (FAILED(result))
{
return gl::OutOfMemory() << "Failed to map internal vertex buffer for texture copy, "
<< result;
}
UINT stride = 0;
UINT startIdx = 0;
UINT drawCount = 0;
D3D11_PRIMITIVE_TOPOLOGY topology;
Write2DVertices(sourceArea, sourceSize, destArea, destSize, mappedResource.pData, &stride,
&drawCount, &topology);
deviceContext->Unmap(mVertexBuffer.Get(), 0);
// Apply vertex buffer
deviceContext->IASetVertexBuffers(0, 1, mVertexBuffer.GetAddressOf(), &stride, &startIdx);
// Apply state
deviceContext->OMSetBlendState(nullptr, nullptr, 0xFFFFFFF);
deviceContext->OMSetDepthStencilState(mDepthStencilState.Get(), 0xFFFFFFFF);
if (scissor)
{
D3D11_RECT scissorRect;
scissorRect.left = scissor->x;
scissorRect.right = scissor->x + scissor->width;
scissorRect.top = scissor->y;
scissorRect.bottom = scissor->y + scissor->height;
deviceContext->RSSetScissorRects(1, &scissorRect);
deviceContext->RSSetState(mScissorEnabledRasterizerState.Get());
}
else
{
deviceContext->RSSetState(mScissorDisabledRasterizerState.Get());
}
ID3D11Device *device = mRenderer->getDevice();
ID3D11VertexShader *quad2DVS = mQuad2DVS.resolve(device);
if (quad2DVS == nullptr)
{
return gl::InternalError() << "Error compiling internal 2D blit vertex shader";
}
// Apply shaders
deviceContext->IASetInputLayout(mQuad2DIL.resolve(device));
deviceContext->IASetPrimitiveTopology(topology);
deviceContext->VSSetShader(quad2DVS, nullptr, 0);
deviceContext->PSSetShader(mDepthPS.resolve(device), nullptr, 0);
deviceContext->GSSetShader(nullptr, nullptr, 0);
// Unset the currently bound shader resource to avoid conflicts
auto stateManager = mRenderer->getStateManager();
stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, nullptr);
// Apply render target
stateManager->setOneTimeRenderTarget(nullptr, dest);
// Set the viewport
D3D11_VIEWPORT viewport;
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = static_cast<FLOAT>(destSize.width);
viewport.Height = static_cast<FLOAT>(destSize.height);
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
deviceContext->RSSetViewports(1, &viewport);
// Apply textures
stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, source);
// Apply samplers
deviceContext->PSSetSamplers(0, 1, mPointSampler.GetAddressOf());
// Draw the quad
deviceContext->Draw(drawCount, 0);
// Unbind textures and render targets and vertex buffer
stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, nullptr);
UINT zero = 0;
ID3D11Buffer *const nullBuffer = nullptr;
deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero);
mRenderer->markAllStateDirty();
return gl::NoError();
}
gl::Error Blit11::copyDepthStencil(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(source, sourceSubresource, sourceArea, sourceSize, dest,
destSubresource, destArea, destSize, scissor, false);
}
gl::Error Blit11::copyDepthStencilImpl(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(source, sourceSubresource, sourceArea, sourceSize, dest,
destSubresource, destArea, destSize, scissor, copyOffset,
copyOffset, copySize, srcPixelSize, destPixelSize,
BlitD24S8ToD32F);
}
ASSERT(srcDXGIFormat == DXGI_FORMAT_R32G8X24_TYPELESS);
return copyAndConvert(source, sourceSubresource, sourceArea, sourceSize, dest,
destSubresource, destArea, destSize, scissor, copyOffset, copyOffset,
copySize, srcPixelSize, destPixelSize, BlitD32FS8ToD32F);
}
return copyAndConvert(source, sourceSubresource, sourceArea, sourceSize, dest, destSubresource,
destArea, destSize, scissor, copyOffset, copyOffset, copySize,
srcPixelSize, destPixelSize, StretchedBlitNearest);
}
gl::Error Blit11::copyAndConvertImpl(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());
ID3D11Device *device = mRenderer->getDevice();
ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
TextureHelper11 sourceStaging;
ANGLE_TRY_RESULT(CreateStagingTexture(GL_TEXTURE_2D, source.getFormatSet(), sourceSize,
StagingAccess::READ, device),
sourceStaging);
deviceContext->CopySubresourceRegion(sourceStaging.getResource(), 0, 0, 0, 0,
source.getResource(), sourceSubresource, nullptr);
D3D11_MAPPED_SUBRESOURCE sourceMapping;
HRESULT result =
deviceContext->Map(sourceStaging.getResource(), 0, D3D11_MAP_READ, 0, &sourceMapping);
if (FAILED(result))
{
return gl::OutOfMemory()
<< "Failed to map internal source staging texture for depth stencil blit, "
<< result;
}
D3D11_MAPPED_SUBRESOURCE destMapping;
result = deviceContext->Map(destStaging.getResource(), 0, D3D11_MAP_WRITE, 0, &destMapping);
if (FAILED(result))
{
deviceContext->Unmap(sourceStaging.getResource(), 0);
return gl::OutOfMemory()
<< "Failed to map internal destination staging texture for depth stencil blit, "
<< result;
}
// 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)
{
gl::ClipRectangle(clipRect, *scissor, &clipRect);
}
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.getResource(), 0);
deviceContext->Unmap(destStaging.getResource(), 0);
return gl::NoError();
}
gl::Error Blit11::copyAndConvert(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());
ID3D11Device *device = mRenderer->getDevice();
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_RESULT(CreateStagingTexture(GL_TEXTURE_2D, dest.getFormatSet(), destSize,
StagingAccess::READ_WRITE, device),
destStaging);
deviceContext->CopySubresourceRegion(destStaging.getResource(), 0, 0, 0, 0, dest.getResource(),
destSubresource, nullptr);
copyAndConvertImpl(source, sourceSubresource, sourceArea, sourceSize, destStaging, destArea,
destSize, scissor, readOffset, writeOffset, copySize, srcPixelStride,
destPixelStride, convertFunction);
// Work around timeouts/TDRs in older NVIDIA drivers.
if (mRenderer->getWorkarounds().depthStencilBlitExtraCopy)
{
D3D11_MAPPED_SUBRESOURCE mapped;
deviceContext->Map(destStaging.getResource(), 0, D3D11_MAP_READ, 0, &mapped);
deviceContext->UpdateSubresource(dest.getResource(), destSubresource, nullptr, mapped.pData,
mapped.RowPitch, mapped.DepthPitch);
deviceContext->Unmap(destStaging.getResource(), 0);
}
else
{
deviceContext->CopySubresourceRegion(dest.getResource(), destSubresource, 0, 0, 0,
destStaging.getResource(), 0, nullptr);
}
return gl::NoError();
}
void Blit11::addBlitShaderToMap(BlitShaderType blitShaderType,
ShaderDimension dimension,
ID3D11PixelShader *ps)
{
ASSERT(mBlitShaderMap.find(blitShaderType) == mBlitShaderMap.end());
ASSERT(ps);
Shader shader;
shader.dimension = dimension;
shader.pixelShader = ps;
mBlitShaderMap[blitShaderType] = shader;
}
void Blit11::addSwizzleShaderToMap(SwizzleShaderType swizzleShaderType,
ShaderDimension dimension,
ID3D11PixelShader *ps)
{
ASSERT(mSwizzleShaderMap.find(swizzleShaderType) == mSwizzleShaderMap.end());
ASSERT(ps);
Shader shader;
shader.dimension = dimension;
shader.pixelShader = ps;
mSwizzleShaderMap[swizzleShaderType] = shader;
}
void Blit11::clearShaderMap()
{
for (auto &blitShader : mBlitShaderMap)
{
SafeRelease(blitShader.second.pixelShader);
}
mBlitShaderMap.clear();
for (auto &swizzleShader : mSwizzleShaderMap)
{
SafeRelease(swizzleShader.second.pixelShader);
}
mSwizzleShaderMap.clear();
}
gl::Error Blit11::getBlitShader(GLenum destFormat,
bool isSigned,
bool unpackPremultiplyAlpha,
bool unpackUnmultiplyAlpha,
ShaderDimension dimension,
const Shader **shader)
{
BlitShaderType blitShaderType = GetBlitShaderType(destFormat, isSigned, unpackPremultiplyAlpha,
unpackUnmultiplyAlpha, dimension);
if (blitShaderType == BLITSHADER_INVALID)
{
return gl::InternalError() << "Internal blit shader type mismatch";
}
auto blitShaderIt = mBlitShaderMap.find(blitShaderType);
if (blitShaderIt != mBlitShaderMap.end())
{
*shader = &blitShaderIt->second;
return gl::NoError();
}
ASSERT(dimension == SHADER_2D || mRenderer->isES3Capable());
ID3D11Device *device = mRenderer->getDevice();
switch (blitShaderType)
{
case BLITSHADER_2D_RGBAF:
addBlitShaderToMap(
blitShaderType, SHADER_2D,
d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D RGBA pixel shader"));
break;
case BLITSHADER_2D_RGBAF_PREMULTIPLY:
addBlitShaderToMap(blitShaderType, SHADER_2D,
d3d11::CompilePS(device, g_PS_PassthroughRGBAPremultiply2D,
"Blit11 2D RGBA premultiply pixel shader"));
break;
case BLITSHADER_2D_RGBAF_UNMULTIPLY:
addBlitShaderToMap(blitShaderType, SHADER_2D,
d3d11::CompilePS(device, g_PS_PassthroughRGBAUnmultiply2D,
"Blit11 2D RGBA unmultiply pixel shader"));
break;
case BLITSHADER_2D_BGRAF:
addBlitShaderToMap(
blitShaderType, SHADER_2D,
d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D BGRA pixel shader"));
break;
case BLITSHADER_2D_BGRAF_PREMULTIPLY:
addBlitShaderToMap(blitShaderType, SHADER_2D,
d3d11::CompilePS(device, g_PS_PassthroughRGBAPremultiply2D,
"Blit11 2D BGRA premultiply pixel shader"));
break;
case BLITSHADER_2D_BGRAF_UNMULTIPLY:
addBlitShaderToMap(blitShaderType, SHADER_2D,
d3d11::CompilePS(device, g_PS_PassthroughRGBAUnmultiply2D,
"Blit11 2D BGRA unmultiply pixel shader"));
break;
case BLITSHADER_2D_RGBF:
addBlitShaderToMap(
blitShaderType, SHADER_2D,
d3d11::CompilePS(device, g_PS_PassthroughRGB2D, "Blit11 2D RGB pixel shader"));
break;
case BLITSHADER_2D_RGBF_PREMULTIPLY:
addBlitShaderToMap(blitShaderType, SHADER_2D,
d3d11::CompilePS(device, g_PS_PassthroughRGBPremultiply2D,
"Blit11 2D RGB premultiply pixel shader"));
break;
case BLITSHADER_2D_RGBF_UNMULTIPLY:
addBlitShaderToMap(blitShaderType, SHADER_2D,
d3d11::CompilePS(device, g_PS_PassthroughRGBUnmultiply2D,
"Blit11 2D RGB unmultiply pixel shader"));
break;
case BLITSHADER_2D_RGF:
addBlitShaderToMap(
blitShaderType, SHADER_2D,
d3d11::CompilePS(device, g_PS_PassthroughRG2D, "Blit11 2D RG pixel shader"));
break;
case BLITSHADER_2D_RF:
addBlitShaderToMap(
blitShaderType, SHADER_2D,
d3d11::CompilePS(device, g_PS_PassthroughR2D, "Blit11 2D R pixel shader"));
break;
case BLITSHADER_2D_ALPHA:
addBlitShaderToMap(
blitShaderType, SHADER_2D,
d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D alpha pixel shader"));
break;
case BLITSHADER_2D_LUMA:
addBlitShaderToMap(
blitShaderType, SHADER_2D,
d3d11::CompilePS(device, g_PS_PassthroughLum2D, "Blit11 2D lum pixel shader"));
break;
case BLITSHADER_2D_LUMAALPHA:
addBlitShaderToMap(blitShaderType, SHADER_2D,
d3d11::CompilePS(device, g_PS_PassthroughLumAlpha2D,
"Blit11 2D luminance alpha pixel shader"));
break;
case BLITSHADER_2D_RGBAUI:
addBlitShaderToMap(blitShaderType, SHADER_2D,
d3d11::CompilePS(device, g_PS_PassthroughRGBA2DUI,
"Blit11 2D RGBA UI pixel shader"));
break;
case BLITSHADER_2D_RGBAI:
addBlitShaderToMap(
blitShaderType, SHADER_2D,
d3d11::CompilePS(device, g_PS_PassthroughRGBA2DI, "Blit11 2D RGBA I pixel shader"));
break;
case BLITSHADER_2D_RGBUI:
addBlitShaderToMap(
blitShaderType, SHADER_2D,
d3d11::CompilePS(device, g_PS_PassthroughRGB2DUI, "Blit11 2D RGB UI pixel shader"));
break;
case BLITSHADER_2D_RGBI:
addBlitShaderToMap(
blitShaderType, SHADER_2D,
d3d11::CompilePS(device, g_PS_PassthroughRGB2DI, "Blit11 2D RGB I pixel shader"));
break;
case BLITSHADER_2D_RGUI:
addBlitShaderToMap(
blitShaderType, SHADER_2D,
d3d11::CompilePS(device, g_PS_PassthroughRG2DUI, "Blit11 2D RG UI pixel shader"));
break;
case BLITSHADER_2D_RGI:
addBlitShaderToMap(
blitShaderType, SHADER_2D,
d3d11::CompilePS(device, g_PS_PassthroughRG2DI, "Blit11 2D RG I pixel shader"));
break;
case BLITSHADER_2D_RUI:
addBlitShaderToMap(
blitShaderType, SHADER_2D,
d3d11::CompilePS(device, g_PS_PassthroughR2DUI, "Blit11 2D R UI pixel shader"));
break;
case BLITSHADER_2D_RI:
addBlitShaderToMap(
blitShaderType, SHADER_2D,
d3d11::CompilePS(device, g_PS_PassthroughR2DI, "Blit11 2D R I pixel shader"));
break;
case BLITSHADER_3D_RGBAF:
addBlitShaderToMap(
blitShaderType, SHADER_3D,
d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D RGBA pixel shader"));
break;
case BLITSHADER_3D_RGBAUI:
addBlitShaderToMap(blitShaderType, SHADER_3D,
d3d11::CompilePS(device, g_PS_PassthroughRGBA3DUI,
"Blit11 3D UI RGBA pixel shader"));
break;
case BLITSHADER_3D_RGBAI:
addBlitShaderToMap(
blitShaderType, SHADER_3D,
d3d11::CompilePS(device, g_PS_PassthroughRGBA3DI, "Blit11 3D I RGBA pixel shader"));
break;
case BLITSHADER_3D_BGRAF:
addBlitShaderToMap(
blitShaderType, SHADER_3D,
d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D BGRA pixel shader"));
break;
case BLITSHADER_3D_RGBF:
addBlitShaderToMap(
blitShaderType, SHADER_3D,
d3d11::CompilePS(device, g_PS_PassthroughRGB3D, "Blit11 3D RGB pixel shader"));
break;
case BLITSHADER_3D_RGBUI:
addBlitShaderToMap(
blitShaderType, SHADER_3D,
d3d11::CompilePS(device, g_PS_PassthroughRGB3DUI, "Blit11 3D RGB UI pixel shader"));
break;
case BLITSHADER_3D_RGBI:
addBlitShaderToMap(
blitShaderType, SHADER_3D,
d3d11::CompilePS(device, g_PS_PassthroughRGB3DI, "Blit11 3D RGB I pixel shader"));
break;
case BLITSHADER_3D_RGF:
addBlitShaderToMap(
blitShaderType, SHADER_3D,
d3d11::CompilePS(device, g_PS_PassthroughRG3D, "Blit11 3D RG pixel shader"));
break;
case BLITSHADER_3D_RGUI:
addBlitShaderToMap(
blitShaderType, SHADER_3D,
d3d11::CompilePS(device, g_PS_PassthroughRG3DUI, "Blit11 3D RG UI pixel shader"));
break;
case BLITSHADER_3D_RGI:
addBlitShaderToMap(
blitShaderType, SHADER_3D,
d3d11::CompilePS(device, g_PS_PassthroughRG3DI, "Blit11 3D RG I pixel shader"));
break;
case BLITSHADER_3D_RF:
addBlitShaderToMap(
blitShaderType, SHADER_3D,
d3d11::CompilePS(device, g_PS_PassthroughR3D, "Blit11 3D R pixel shader"));
break;
case BLITSHADER_3D_RUI:
addBlitShaderToMap(
blitShaderType, SHADER_3D,
d3d11::CompilePS(device, g_PS_PassthroughR3DUI, "Blit11 3D R UI pixel shader"));
break;
case BLITSHADER_3D_RI:
addBlitShaderToMap(
blitShaderType, SHADER_3D,
d3d11::CompilePS(device, g_PS_PassthroughR3DI, "Blit11 3D R I pixel shader"));
break;
case BLITSHADER_3D_ALPHA:
addBlitShaderToMap(
blitShaderType, SHADER_3D,
d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D alpha pixel shader"));
break;
case BLITSHADER_3D_LUMA:
addBlitShaderToMap(blitShaderType, SHADER_3D,
d3d11::CompilePS(device, g_PS_PassthroughLum3D,
"Blit11 3D luminance pixel shader"));
break;
case BLITSHADER_3D_LUMAALPHA:
addBlitShaderToMap(blitShaderType, SHADER_3D,
d3d11::CompilePS(device, g_PS_PassthroughLumAlpha3D,
"Blit11 3D luminance alpha pixel shader"));
break;
default:
UNREACHABLE();
return gl::InternalError() << "Internal error";
}
blitShaderIt = mBlitShaderMap.find(blitShaderType);
ASSERT(blitShaderIt != mBlitShaderMap.end());
*shader = &blitShaderIt->second;
return gl::NoError();
}
gl::Error Blit11::getSwizzleShader(GLenum type,
D3D11_SRV_DIMENSION viewDimension,
const Shader **shader)
{
SwizzleShaderType swizzleShaderType = GetSwizzleShaderType(type, viewDimension);
if (swizzleShaderType == SWIZZLESHADER_INVALID)
{
return gl::InternalError() << "Swizzle shader type not found";
}
auto swizzleShaderIt = mSwizzleShaderMap.find(swizzleShaderType);
if (swizzleShaderIt != mSwizzleShaderMap.end())
{
*shader = &swizzleShaderIt->second;
return gl::NoError();
}
// Swizzling shaders (OpenGL ES 3+)
ASSERT(mRenderer->isES3Capable());
ID3D11Device *device = mRenderer->getDevice();
switch (swizzleShaderType)
{
case SWIZZLESHADER_2D_FLOAT:
addSwizzleShaderToMap(
swizzleShaderType, SHADER_2D,
d3d11::CompilePS(device, g_PS_SwizzleF2D, "Blit11 2D F swizzle pixel shader"));
break;
case SWIZZLESHADER_2D_UINT:
addSwizzleShaderToMap(
swizzleShaderType, SHADER_2D,
d3d11::CompilePS(device, g_PS_SwizzleUI2D, "Blit11 2D UI swizzle pixel shader"));
break;
case SWIZZLESHADER_2D_INT:
addSwizzleShaderToMap(
swizzleShaderType, SHADER_2D,
d3d11::CompilePS(device, g_PS_SwizzleI2D, "Blit11 2D I swizzle pixel shader"));
break;
case SWIZZLESHADER_CUBE_FLOAT:
addSwizzleShaderToMap(swizzleShaderType, SHADER_3D,
d3d11::CompilePS(device, g_PS_SwizzleF2DArray,
"Blit11 2D Cube F swizzle pixel shader"));
break;
case SWIZZLESHADER_CUBE_UINT:
addSwizzleShaderToMap(swizzleShaderType, SHADER_3D,
d3d11::CompilePS(device, g_PS_SwizzleUI2DArray,
"Blit11 2D Cube UI swizzle pixel shader"));
break;
case SWIZZLESHADER_CUBE_INT:
addSwizzleShaderToMap(swizzleShaderType, SHADER_3D,
d3d11::CompilePS(device, g_PS_SwizzleI2DArray,
"Blit11 2D Cube I swizzle pixel shader"));
break;
case SWIZZLESHADER_3D_FLOAT:
addSwizzleShaderToMap(
swizzleShaderType, SHADER_3D,
d3d11::CompilePS(device, g_PS_SwizzleF3D, "Blit11 3D F swizzle pixel shader"));
break;
case SWIZZLESHADER_3D_UINT:
addSwizzleShaderToMap(
swizzleShaderType, SHADER_3D,
d3d11::CompilePS(device, g_PS_SwizzleUI3D, "Blit11 3D UI swizzle pixel shader"));
break;
case SWIZZLESHADER_3D_INT:
addSwizzleShaderToMap(
swizzleShaderType, SHADER_3D,
d3d11::CompilePS(device, g_PS_SwizzleI3D, "Blit11 3D I swizzle pixel shader"));
break;
case SWIZZLESHADER_ARRAY_FLOAT:
addSwizzleShaderToMap(swizzleShaderType, SHADER_3D,
d3d11::CompilePS(device, g_PS_SwizzleF2DArray,
"Blit11 2D Array F swizzle pixel shader"));
break;
case SWIZZLESHADER_ARRAY_UINT:
addSwizzleShaderToMap(swizzleShaderType, SHADER_3D,
d3d11::CompilePS(device, g_PS_SwizzleUI2DArray,
"Blit11 2D Array UI swizzle pixel shader"));
break;
case SWIZZLESHADER_ARRAY_INT:
addSwizzleShaderToMap(swizzleShaderType, SHADER_3D,
d3d11::CompilePS(device, g_PS_SwizzleI2DArray,
"Blit11 2D Array I swizzle pixel shader"));
break;
default:
UNREACHABLE();
return gl::InternalError() << "Internal error";
}
swizzleShaderIt = mSwizzleShaderMap.find(swizzleShaderType);
ASSERT(swizzleShaderIt != mSwizzleShaderMap.end());
*shader = &swizzleShaderIt->second;
return gl::NoError();
}
gl::ErrorOrResult<TextureHelper11> Blit11::resolveDepth(RenderTarget11 *depth)
{
// 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();
ID3D11Device *device = mRenderer->getDevice();
ID3D11DeviceContext *context = mRenderer->getDeviceContext();
ANGLE_TRY(initResolveDepthOnly(depth->getFormatSet(), extents));
// Notify the Renderer that all state should be invalidated.
mRenderer->markAllStateDirty();
// Apply the necessary state changes to the D3D11 immediate device context.
context->IASetInputLayout(nullptr);
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
context->VSSetShader(mResolveDepthStencilVS.resolve(device), nullptr, 0);
context->GSSetShader(nullptr, nullptr, 0);
context->RSSetState(nullptr);
context->OMSetDepthStencilState(mDepthStencilState.Get(), 0xFFFFFFFF);
context->OMSetRenderTargets(0, nullptr, mResolvedDepthDSView.Get());
context->OMSetBlendState(nullptr, nullptr, 0xFFFFFFF);
// Set the viewport
D3D11_VIEWPORT viewport;
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = static_cast<FLOAT>(extents.width);
viewport.Height = static_cast<FLOAT>(extents.height);
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
context->RSSetViewports(1, &viewport);
ID3D11ShaderResourceView *pixelViews[] = {depth->getShaderResourceView()};
context->PSSetShaderResources(0, 1, pixelViews);
context->PSSetShader(mResolveDepthPS.resolve(device), nullptr, 0);
// Trigger the blit on the GPU.
context->Draw(6, 0);
return TextureHelper11::MakeAndReference(mResolvedDepth.getResource(),
mResolvedDepth.getFormatSet());
}
gl::Error Blit11::initResolveDepthOnly(const d3d11::Format &format, const gl::Extents &extents)
{
if (mResolvedDepth.valid() && extents == mResolvedDepth.getExtents() &&
format.texFormat == mResolvedDepth.getFormat())
{
return gl::NoError();
}
ID3D11Device *device = mRenderer->getDevice();
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;
ID3D11Texture2D *resolvedDepth = nullptr;
HRESULT hr = device->CreateTexture2D(&textureDesc, nullptr, &resolvedDepth);
if (FAILED(hr))
{
return gl::OutOfMemory() << "Failed to allocate resolved depth texture, " << hr;
}
d3d11::SetDebugName(resolvedDepth, "Blit11::mResolvedDepth");
mResolvedDepth = TextureHelper11::MakeAndPossess2D(resolvedDepth, format);
D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
dsvDesc.Flags = 0;
dsvDesc.Format = format.dsvFormat;
dsvDesc.Texture2D.MipSlice = 0;
dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
hr = device->CreateDepthStencilView(mResolvedDepth.getResource(), &dsvDesc,
mResolvedDepthDSView.ReleaseAndGetAddressOf());
if (FAILED(hr))
{
return gl::OutOfMemory() << "Failed to allocate Blit11::mResolvedDepthDSView, " << hr;
}
d3d11::SetDebugName(mResolvedDepthDSView, "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.
auto context = mRenderer->getDeviceContext();
context->ClearDepthStencilView(mResolvedDepthDSView.Get(), D3D11_CLEAR_DEPTH, 1.0f, 0);
return gl::NoError();
}
gl::Error Blit11::initResolveDepthStencil(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 gl::NoError();
}
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;
ID3D11Device *device = mRenderer->getDevice();
ID3D11Texture2D *resolvedDepthStencil = nullptr;
HRESULT hr = device->CreateTexture2D(&textureDesc, nullptr, &resolvedDepthStencil);
if (FAILED(hr))
{
return gl::OutOfMemory() << "Failed to allocate resolved depth stencil texture, " << hr;
}
d3d11::SetDebugName(resolvedDepthStencil, "Blit11::mResolvedDepthStencil");
ANGLE_TRY(
mRenderer->allocateResourceNoDesc(resolvedDepthStencil, &mResolvedDepthStencilRTView));
mResolvedDepthStencilRTView.setDebugName("Blit11::mResolvedDepthStencilRTView");
mResolvedDepthStencil = TextureHelper11::MakeAndPossess2D(resolvedDepthStencil, formatSet);
return gl::NoError();
}
gl::ErrorOrResult<TextureHelper11> Blit11::resolveStencil(RenderTarget11 *depthStencil,
bool alsoDepth)
{
// 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(extents));
ID3D11Device *device = mRenderer->getDevice();
ID3D11DeviceContext *context = mRenderer->getDeviceContext();
ID3D11Resource *stencilResource = depthStencil->getTexture();
// Check if we need to re-create the stencil SRV.
if (mStencilSRV)
{
ID3D11Resource *priorResource = nullptr;
mStencilSRV->GetResource(&priorResource);
if (stencilResource != priorResource)
{
mStencilSRV.Reset();
}
SafeRelease(priorResource);
}
if (mStencilSRV == nullptr)
{
D3D11_SHADER_RESOURCE_VIEW_DESC srViewDesc;
srViewDesc.Format = GetStencilSRVFormat(depthStencil->getFormatSet());
srViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS;
HRESULT hr = device->CreateShaderResourceView(stencilResource, &srViewDesc,
mStencilSRV.GetAddressOf());
if (FAILED(hr))
{
return gl::OutOfMemory() << "Error creating Blit11 stencil SRV, " << hr;
}
d3d11::SetDebugName(mStencilSRV, "Blit11::mStencilSRV");
}
// Notify the Renderer that all state should be invalidated.
mRenderer->markAllStateDirty();
ID3D11RenderTargetView *rtvs[] = {mResolvedDepthStencilRTView.get()};
// Apply the necessary state changes to the D3D11 immediate device context.
context->IASetInputLayout(nullptr);
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
context->VSSetShader(mResolveDepthStencilVS.resolve(device), nullptr, 0);
context->GSSetShader(nullptr, nullptr, 0);
context->RSSetState(nullptr);
context->OMSetDepthStencilState(nullptr, 0xFFFFFFFF);
context->OMSetRenderTargets(1, rtvs, nullptr);
context->OMSetBlendState(nullptr, nullptr, 0xFFFFFFF);
// Set the viewport
D3D11_VIEWPORT viewport;
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = static_cast<FLOAT>(extents.width);
viewport.Height = static_cast<FLOAT>(extents.height);
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
context->RSSetViewports(1, &viewport);
ID3D11ShaderResourceView *pixelViews[] = {
depthStencil->getShaderResourceView(), mStencilSRV.Get(),
};
context->PSSetShaderResources(0, 2, pixelViews);
// 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.
if (alsoDepth)
{
context->PSSetShader(mResolveDepthStencilPS.resolve(device), nullptr, 0);
}
else
{
context->PSSetShader(mResolveStencilPS.resolve(device), nullptr, 0);
}
// Trigger the blit on the GPU.
context->Draw(6, 0);
gl::Box copyBox(0, 0, 0, extents.width, extents.height, 1);
TextureHelper11 dest;
ANGLE_TRY_RESULT(CreateStagingTexture(GL_TEXTURE_2D, depthStencil->getFormatSet(), extents,
StagingAccess::READ_WRITE, device),
dest);
const auto &copyFunction = GetCopyDepthStencilFunction(depthStencil->getInternalFormat());
const auto &dsFormatSet = depthStencil->getFormatSet();
const auto &dsDxgiInfo = d3d11::GetDXGIFormatSizeInfo(dsFormatSet.texFormat);
ANGLE_TRY(copyAndConvertImpl(mResolvedDepthStencil, 0, copyBox, extents, dest, copyBox, extents,
nullptr, 0, 0, 0, 8u, dsDxgiInfo.pixelBytes, copyFunction));
// Return the resolved depth texture, which the caller must Release.
return dest;
}
void Blit11::releaseResolveDepthStencilResources()
{
mStencilSRV.Reset();
mResolvedDepthStencilRTView.reset();
}
} // namespace rx