Commit 9e3d7aa0 by Jamie Madill

D3D11: Work around small mipped stencil textures.

AMD has a bug with 2x2 and 1x1 mips of depth/stencil textures. Formats D24S8 and D32FS8 both seem to render black for the very small mips. We can work around this by selectively caching a copy of the texture data that only has depth information, since stencil isn't filterable in OpenGL ES. BUG=angleproject:1493 BUG=chromium:638323 Change-Id: Iebef42c4680018d9854dbe789d677823167213dd Reviewed-on: https://chromium-review.googlesource.com/380037Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 6a25746c
...@@ -75,6 +75,11 @@ struct WorkaroundsD3D ...@@ -75,6 +75,11 @@ struct WorkaroundsD3D
// and Offset is in range. To work around this, we translatie texelFetchOffset into texelFetch // and Offset is in range. To work around this, we translatie texelFetchOffset into texelFetch
// by adding Offset directly to Location before reading the texture. // by adding Offset directly to Location before reading the texture.
bool preAddTexelFetchOffsets = false; bool preAddTexelFetchOffsets = false;
// On some AMD drivers, 1x1 and 2x2 mips of depth/stencil textures aren't sampled correctly.
// We can work around this bug by doing an internal blit to a temporary single-channel texture
// before we sample.
bool emulateTinyStencilTextures = false;
}; };
} // namespace rx } // namespace rx
......
...@@ -274,6 +274,93 @@ void CopyDepthStencil(const gl::Box &sourceArea, ...@@ -274,6 +274,93 @@ void CopyDepthStencil(const gl::Box &sourceArea,
} }
} }
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) Blit11::BlitConvertFunction *GetCopyDepthStencilFunction(GLenum internalFormat)
{ {
switch (internalFormat) switch (internalFormat)
...@@ -1381,7 +1468,7 @@ gl::Error Blit11::copyDepthStencilImpl(const TextureHelper11 &source, ...@@ -1381,7 +1468,7 @@ gl::Error Blit11::copyDepthStencilImpl(const TextureHelper11 &source,
const auto &destSizeInfo = d3d11::GetDXGIFormatSizeInfo(destFormat); const auto &destSizeInfo = d3d11::GetDXGIFormatSizeInfo(destFormat);
unsigned int destPixelSize = destSizeInfo.pixelBytes; unsigned int destPixelSize = destSizeInfo.pixelBytes;
ASSERT(srcFormat == destFormat); ASSERT(srcFormat == destFormat || destFormat == DXGI_FORMAT_R32_TYPELESS);
if (stencilOnly) if (stencilOnly)
{ {
...@@ -1400,6 +1487,22 @@ gl::Error Blit11::copyDepthStencilImpl(const TextureHelper11 &source, ...@@ -1400,6 +1487,22 @@ gl::Error Blit11::copyDepthStencilImpl(const TextureHelper11 &source,
copySize = 1; copySize = 1;
} }
if (srcFormat != destFormat)
{
if (srcFormat == 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(srcFormat == 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, return copyAndConvert(source, sourceSubresource, sourceArea, sourceSize, dest, destSubresource,
destArea, destSize, scissor, copyOffset, copyOffset, copySize, destArea, destSize, scissor, copyOffset, copyOffset, copySize,
srcPixelSize, destPixelSize, StretchedBlitNearest); srcPixelSize, destPixelSize, StretchedBlitNearest);
......
...@@ -3079,7 +3079,7 @@ gl::Error Renderer11::copyTexture(const gl::Texture *source, ...@@ -3079,7 +3079,7 @@ gl::Error Renderer11::copyTexture(const gl::Texture *source,
destStorage11->markLevelDirty(destLevel); destStorage11->markLevelDirty(destLevel);
return gl::Error(GL_NO_ERROR); return gl::NoError();
} }
gl::Error Renderer11::createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTargetD3D **outRT) gl::Error Renderer11::createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTargetD3D **outRT)
...@@ -3541,16 +3541,12 @@ gl::Error Renderer11::generateMipmapUsingD3D(TextureStorage *storage, ...@@ -3541,16 +3541,12 @@ gl::Error Renderer11::generateMipmapUsingD3D(TextureStorage *storage,
ASSERT(storage11->supportsNativeMipmapFunction()); ASSERT(storage11->supportsNativeMipmapFunction());
ID3D11ShaderResourceView *srv; ID3D11ShaderResourceView *srv;
gl::Error error = storage11->getSRVLevels(textureState.getEffectiveBaseLevel(), ANGLE_TRY(storage11->getSRVLevels(textureState.getEffectiveBaseLevel(),
textureState.getEffectiveMaxLevel(), &srv); textureState.getEffectiveMaxLevel(), &srv));
if (error.isError())
{
return error;
}
mDeviceContext->GenerateMips(srv); mDeviceContext->GenerateMips(srv);
return gl::Error(GL_NO_ERROR); return gl::NoError();
} }
TextureStorage *Renderer11::createTextureStorage2D(SwapChainD3D *swapChain) TextureStorage *Renderer11::createTextureStorage2D(SwapChainD3D *swapChain)
......
...@@ -94,6 +94,10 @@ class TextureStorage11 : public TextureStorage ...@@ -94,6 +94,10 @@ class TextureStorage11 : public TextureStorage
virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) = 0; virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) = 0;
gl::Error getSRVLevel(int mipLevel, bool blitSRV, ID3D11ShaderResourceView **outSRV); gl::Error getSRVLevel(int mipLevel, bool blitSRV, ID3D11ShaderResourceView **outSRV);
// Get a version of a depth texture with only depth information, not stencil.
virtual gl::Error createDropStencilTexture();
gl::Error initDropStencilTexture(const gl::ImageIndexIterator &it);
// The baseLevel parameter should *not* have mTopLevel applied. // The baseLevel parameter should *not* have mTopLevel applied.
virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture,
ID3D11ShaderResourceView **outSRV) const = 0; ID3D11ShaderResourceView **outSRV) const = 0;
...@@ -113,6 +117,7 @@ class TextureStorage11 : public TextureStorage ...@@ -113,6 +117,7 @@ class TextureStorage11 : public TextureStorage
unsigned int mTextureDepth; unsigned int mTextureDepth;
gl::SwizzleState mSwizzleCache[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; gl::SwizzleState mSwizzleCache[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
ID3D11Texture2D *mDropStencilTexture;
private: private:
const UINT mBindFlags; const UINT mBindFlags;
...@@ -120,13 +125,14 @@ class TextureStorage11 : public TextureStorage ...@@ -120,13 +125,14 @@ class TextureStorage11 : public TextureStorage
struct SRVKey struct SRVKey
{ {
SRVKey(int baseLevel = 0, int mipLevels = 0, bool swizzle = false); SRVKey(int baseLevel, int mipLevels, bool swizzle, bool dropStencil);
bool operator<(const SRVKey &rhs) const; bool operator<(const SRVKey &rhs) const;
int baseLevel; // Without mTopLevel applied. int baseLevel = 0; // Without mTopLevel applied.
int mipLevels; int mipLevels = 0;
bool swizzle; bool swizzle = false;
bool dropStencil = false;
}; };
typedef std::map<SRVKey, ID3D11ShaderResourceView *> SRVCache; typedef std::map<SRVKey, ID3D11ShaderResourceView *> SRVCache;
...@@ -142,30 +148,35 @@ class TextureStorage11_2D : public TextureStorage11 ...@@ -142,30 +148,35 @@ class TextureStorage11_2D : public TextureStorage11
public: public:
TextureStorage11_2D(Renderer11 *renderer, SwapChain11 *swapchain); TextureStorage11_2D(Renderer11 *renderer, SwapChain11 *swapchain);
TextureStorage11_2D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly = false); TextureStorage11_2D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly = false);
virtual ~TextureStorage11_2D(); ~TextureStorage11_2D() override;
virtual gl::Error getResource(ID3D11Resource **outResource); gl::Error getResource(ID3D11Resource **outResource) override;
virtual gl::Error getMippedResource(ID3D11Resource **outResource); gl::Error getMippedResource(ID3D11Resource **outResource) override;
virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) override;
virtual gl::Error copyToStorage(TextureStorage *destStorage); gl::Error copyToStorage(TextureStorage *destStorage) override;
virtual void associateImage(Image11* image, const gl::ImageIndex &index); void associateImage(Image11 *image, const gl::ImageIndex &index) override;
virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage); void disassociateImage(const gl::ImageIndex &index, Image11 *expectedImage) override;
virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage); bool isAssociatedImageValid(const gl::ImageIndex &index, Image11 *expectedImage) override;
virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage); gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11 *incomingImage) override;
virtual gl::Error useLevelZeroWorkaroundTexture(bool useLevelZeroTexture); gl::Error useLevelZeroWorkaroundTexture(bool useLevelZeroTexture) override;
protected: protected:
virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture); gl::Error getSwizzleTexture(ID3D11Resource **outTexture) override;
virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV); gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) override;
gl::Error createDropStencilTexture() override;
gl::Error ensureTextureExists(int mipLevels); gl::Error ensureTextureExists(int mipLevels);
private: private:
virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, gl::Error createSRV(int baseLevel,
ID3D11ShaderResourceView **outSRV) const; int mipLevels,
DXGI_FORMAT format,
ID3D11Resource *texture,
ID3D11ShaderResourceView **outSRV) const override;
ID3D11Texture2D *mTexture; ID3D11Texture2D *mTexture;
RenderTarget11 *mRenderTarget[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; RenderTarget11 *mRenderTarget[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
...@@ -301,6 +312,8 @@ class TextureStorage11_Cube : public TextureStorage11 ...@@ -301,6 +312,8 @@ class TextureStorage11_Cube : public TextureStorage11
virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture); virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture);
virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV); virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV);
gl::Error createDropStencilTexture() override;
gl::Error ensureTextureExists(int mipLevels); gl::Error ensureTextureExists(int mipLevels);
private: private:
...@@ -384,6 +397,8 @@ class TextureStorage11_2DArray : public TextureStorage11 ...@@ -384,6 +397,8 @@ class TextureStorage11_2DArray : public TextureStorage11
virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture); virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture);
virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV); virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV);
gl::Error createDropStencilTexture() override;
private: private:
virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture,
ID3D11ShaderResourceView **outSRV) const; ID3D11ShaderResourceView **outSRV) const;
......
...@@ -1542,6 +1542,9 @@ WorkaroundsD3D GenerateWorkarounds(const Renderer11DeviceCaps &deviceCaps, ...@@ -1542,6 +1542,9 @@ WorkaroundsD3D GenerateWorkarounds(const Renderer11DeviceCaps &deviceCaps,
workarounds.preAddTexelFetchOffsets = (adapterDesc.VendorId == VENDOR_ID_INTEL); workarounds.preAddTexelFetchOffsets = (adapterDesc.VendorId == VENDOR_ID_INTEL);
// TODO(jmadill): Disable when we have a fixed driver version.
workarounds.emulateTinyStencilTextures = (adapterDesc.VendorId == VENDOR_ID_AMD);
return workarounds; return workarounds;
} }
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
// found in the LICENSE file. // found in the LICENSE file.
// //
#include <cmath>
#include "test_utils/ANGLETest.h" #include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h" #include "test_utils/gl_raii.h"
...@@ -3480,6 +3482,61 @@ TEST_P(Texture2DTestES3, UnpackOverlappingRowsFromUnpackBuffer) ...@@ -3480,6 +3482,61 @@ TEST_P(Texture2DTestES3, UnpackOverlappingRowsFromUnpackBuffer)
EXPECT_EQ(expected, actual); EXPECT_EQ(expected, actual);
} }
template <typename T>
T UNorm(double value)
{
return static_cast<T>(value * static_cast<double>(std::numeric_limits<T>::max()));
}
// Test rendering a depth texture with mipmaps.
TEST_P(Texture2DTestES3, DepthTexturesWithMipmaps)
{
const int size = getWindowWidth();
auto dim = [size](int level) { return size >> level; };
int levels = static_cast<int>(std::log2(size));
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mTexture2D);
glTexStorage2D(GL_TEXTURE_2D, levels, GL_DEPTH_COMPONENT24, size, size);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
ASSERT_GL_NO_ERROR();
glUseProgram(mProgram);
glUniform1i(mTexture2DUniformLocation, 0);
std::vector<unsigned char> expected;
for (int level = 0; level < levels; ++level)
{
double value = (static_cast<double>(level) / static_cast<double>(levels - 1));
expected.push_back(UNorm<unsigned char>(value));
int levelDim = dim(level);
ASSERT_GT(levelDim, 0);
std::vector<unsigned int> initData(levelDim * levelDim, UNorm<unsigned int>(value));
glTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, levelDim, levelDim, GL_DEPTH_COMPONENT,
GL_UNSIGNED_INT, initData.data());
}
ASSERT_GL_NO_ERROR();
for (int level = 0; level < levels; ++level)
{
glViewport(0, 0, dim(level), dim(level));
drawQuad(mProgram, "position", 0.5f);
GLColor actual = ReadColor(0, 0);
EXPECT_NEAR(expected[level], actual.R, 10u);
}
ASSERT_GL_NO_ERROR();
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against. // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
// TODO(oetuaho): Enable all below tests on OpenGL. Requires a fix for ANGLE bug 1278. // TODO(oetuaho): Enable all below tests on OpenGL. Requires a fix for ANGLE bug 1278.
ANGLE_INSTANTIATE_TEST(Texture2DTest, ANGLE_INSTANTIATE_TEST(Texture2DTest,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment