Commit ec6de4ec by Jamie Madill

Fix TextureD3D::setData for depth-stencil textures.

D3D11 requires us to NULL the update region parameter when updating depth stencil textures. For these textures, we can't always use the subdata workaround, so disable it entirely for these textures. BUG=angle:729 BUG=365078 Change-Id: I44258dd1b8937b1aebcb3a73de835698805537e0 Reviewed-on: https://chromium-review.googlesource.com/222911Tested-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 24e83192
...@@ -194,4 +194,15 @@ bool VertexFormat::operator<(const VertexFormat& other) const ...@@ -194,4 +194,15 @@ bool VertexFormat::operator<(const VertexFormat& other) const
return mPureInteger < other.mPureInteger; return mPureInteger < other.mPureInteger;
} }
bool Box::operator==(const Box &other) const
{
return (x == other.x && y == other.y && z == other.z &&
width == other.width && height == other.height && depth == other.depth);
}
bool Box::operator!=(const Box &other) const
{
return !(*this == other);
}
} }
...@@ -66,6 +66,8 @@ struct Box ...@@ -66,6 +66,8 @@ struct Box
Box() : x(0), y(0), z(0), width(0), height(0), depth(0) { } Box() : x(0), y(0), z(0), width(0), height(0), depth(0) { }
Box(int x_in, int y_in, int z_in, int width_in, int height_in, int depth_in) : x(x_in), y(y_in), z(z_in), width(width_in), height(height_in), depth(depth_in) { } Box(int x_in, int y_in, int z_in, int width_in, int height_in, int depth_in) : x(x_in), y(y_in), z(z_in), width(width_in), height(height_in), depth(depth_in) { }
bool operator==(const Box &other) const;
bool operator!=(const Box &other) const;
}; };
struct Extents struct Extents
......
...@@ -90,9 +90,30 @@ GLenum TextureD3D::getBaseLevelInternalFormat() const ...@@ -90,9 +90,30 @@ GLenum TextureD3D::getBaseLevelInternalFormat() const
return (baseImage ? baseImage->getInternalFormat() : GL_NONE); return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
} }
bool TextureD3D::shouldUseSetData(const Image *image) const
{
if (!mRenderer->getWorkarounds().setDataFasterThanImageUpload)
{
return false;
}
gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat());
// We can only handle full updates for depth-stencil textures, so to avoid complications
// disable them entirely.
if (internalFormat.depthBits > 0 || internalFormat.stencilBits > 0)
{
return false;
}
// TODO(jmadill): Handle compressed internal formats
return (mTexStorage && !internalFormat.compressed);
}
gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, const gl::ImageIndex &index) gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, const gl::ImageIndex &index)
{ {
Image *image = getImage(index); Image *image = getImage(index);
ASSERT(image);
// No-op // No-op
if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0) if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
...@@ -123,13 +144,9 @@ gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, ...@@ -123,13 +144,9 @@ gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type,
{ {
gl::Error error(GL_NO_ERROR); gl::Error error(GL_NO_ERROR);
gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat()); if (shouldUseSetData(image))
// TODO(jmadill): Handle compressed internal formats
if (mTexStorage && mRenderer->getWorkarounds().setDataFasterThanImageUpload && !internalFormat.compressed)
{ {
gl::Box sourceBox(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth()); error = mTexStorage->setData(index, image, NULL, type, unpack, pixelData);
error = mTexStorage->setData(index, sourceBox, image->getInternalFormat(), type, unpack, pixelData);
} }
else else
{ {
...@@ -168,14 +185,10 @@ gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsi ...@@ -168,14 +185,10 @@ gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsi
Image *image = getImage(index); Image *image = getImage(index);
ASSERT(image); ASSERT(image);
gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat());
gl::Box region(xoffset, yoffset, zoffset, width, height, depth); gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
if (shouldUseSetData(image))
// TODO(jmadill): Handle compressed internal formats
if (mTexStorage && mRenderer->getWorkarounds().setDataFasterThanImageUpload && !internalFormat.compressed)
{ {
return mTexStorage->setData(index, region, image->getInternalFormat(), return mTexStorage->setData(index, image, &region, type, unpack, pixelData);
type, unpack, pixelData);
} }
gl::Error error = image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, gl::Error error = image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment,
......
...@@ -99,6 +99,8 @@ class TextureD3D : public TextureImpl ...@@ -99,6 +99,8 @@ class TextureD3D : public TextureImpl
virtual gl::Error initializeStorage(bool renderTarget) = 0; virtual gl::Error initializeStorage(bool renderTarget) = 0;
virtual gl::Error updateStorage() = 0; virtual gl::Error updateStorage() = 0;
bool shouldUseSetData(const Image *image) const;
}; };
class TextureD3D_2D : public TextureD3D class TextureD3D_2D : public TextureD3D
......
...@@ -27,6 +27,7 @@ namespace rx ...@@ -27,6 +27,7 @@ namespace rx
class Renderer; class Renderer;
class SwapChain; class SwapChain;
class RenderTarget; class RenderTarget;
class Image;
class TextureStorage class TextureStorage
{ {
...@@ -43,7 +44,7 @@ class TextureStorage ...@@ -43,7 +44,7 @@ class TextureStorage
virtual void generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) = 0; virtual void generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) = 0;
virtual gl::Error copyToStorage(TextureStorage *destStorage) = 0; virtual gl::Error copyToStorage(TextureStorage *destStorage) = 0;
virtual gl::Error setData(const gl::ImageIndex &index, const gl::Box &sourceBox, GLenum internalFormat, GLenum type, virtual gl::Error setData(const gl::ImageIndex &index, Image *image, const gl::Box *destBox, GLenum type,
const gl::PixelUnpackState &unpack, const uint8_t *pixelData) = 0; const gl::PixelUnpackState &unpack, const uint8_t *pixelData) = 0;
unsigned int getRenderTargetSerial(const gl::ImageIndex &index) const; unsigned int getRenderTargetSerial(const gl::ImageIndex &index) const;
......
...@@ -422,7 +422,7 @@ gl::Error TextureStorage11::copyToStorage(TextureStorage *destStorage) ...@@ -422,7 +422,7 @@ gl::Error TextureStorage11::copyToStorage(TextureStorage *destStorage)
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
gl::Error TextureStorage11::setData(const gl::ImageIndex &index, const gl::Box &destBox, GLenum internalFormat, GLenum type, gl::Error TextureStorage11::setData(const gl::ImageIndex &index, Image *image, const gl::Box *destBox, GLenum type,
const gl::PixelUnpackState &unpack, const uint8_t *pixelData) const gl::PixelUnpackState &unpack, const uint8_t *pixelData)
{ {
ID3D11Resource *resource = getResource(); ID3D11Resource *resource = getResource();
...@@ -430,7 +430,10 @@ gl::Error TextureStorage11::setData(const gl::ImageIndex &index, const gl::Box & ...@@ -430,7 +430,10 @@ gl::Error TextureStorage11::setData(const gl::ImageIndex &index, const gl::Box &
UINT destSubresource = getSubresourceIndex(index); UINT destSubresource = getSubresourceIndex(index);
const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat); const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(image->getInternalFormat());
bool fullUpdate = (destBox == NULL || *destBox == gl::Box(0, 0, 0, mTextureWidth, mTextureHeight, mTextureDepth));
ASSERT(internalFormatInfo.depthBits == 0 || fullUpdate);
// TODO(jmadill): Handle compressed formats // TODO(jmadill): Handle compressed formats
// Compressed formats have different load syntax, so we'll have to handle them with slightly // Compressed formats have different load syntax, so we'll have to handle them with slightly
...@@ -438,41 +441,56 @@ gl::Error TextureStorage11::setData(const gl::ImageIndex &index, const gl::Box & ...@@ -438,41 +441,56 @@ gl::Error TextureStorage11::setData(const gl::ImageIndex &index, const gl::Box &
// with compressed formats in the calling logic. // with compressed formats in the calling logic.
ASSERT(!internalFormatInfo.compressed); ASSERT(!internalFormatInfo.compressed);
UINT srcRowPitch = internalFormatInfo.computeRowPitch(type, destBox.width, unpack.alignment); int width = destBox ? destBox->width : static_cast<int>(image->getWidth());
UINT srcDepthPitch = internalFormatInfo.computeDepthPitch(type, destBox.width, destBox.height, unpack.alignment); int height = destBox ? destBox->height : static_cast<int>(image->getHeight());
int depth = destBox ? destBox->depth : static_cast<int>(image->getDepth());
D3D11_BOX destD3DBox; UINT srcRowPitch = internalFormatInfo.computeRowPitch(type, width, unpack.alignment);
destD3DBox.left = destBox.x; UINT srcDepthPitch = internalFormatInfo.computeDepthPitch(type, width, height, unpack.alignment);
destD3DBox.right = destBox.x + destBox.width;
destD3DBox.top = destBox.y;
destD3DBox.bottom = destBox.y + destBox.height;
destD3DBox.front = 0;
destD3DBox.back = 1;
const d3d11::TextureFormat &d3d11Format = d3d11::GetTextureFormatInfo(internalFormat); const d3d11::TextureFormat &d3d11Format = d3d11::GetTextureFormatInfo(image->getInternalFormat());
const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(d3d11Format.texFormat); const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(d3d11Format.texFormat);
size_t outputPixelSize = dxgiFormatInfo.pixelBytes; size_t outputPixelSize = dxgiFormatInfo.pixelBytes;
UINT bufferRowPitch = outputPixelSize * destBox.width; UINT bufferRowPitch = outputPixelSize * width;
UINT bufferDepthPitch = bufferRowPitch * destBox.height; UINT bufferDepthPitch = bufferRowPitch * height;
MemoryBuffer conversionBuffer; MemoryBuffer conversionBuffer;
if (!conversionBuffer.resize(bufferDepthPitch * destBox.depth)) if (!conversionBuffer.resize(bufferDepthPitch * depth))
{ {
return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal buffer."); return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal buffer.");
} }
// TODO: fast path // TODO: fast path
LoadImageFunction loadFunction = d3d11Format.loadFunctions.at(type); LoadImageFunction loadFunction = d3d11Format.loadFunctions.at(type);
loadFunction(destBox.width, destBox.height, destBox.depth, loadFunction(width, height, depth,
pixelData, srcRowPitch, srcDepthPitch, pixelData, srcRowPitch, srcDepthPitch,
conversionBuffer.data(), bufferRowPitch, bufferDepthPitch); conversionBuffer.data(), bufferRowPitch, bufferDepthPitch);
ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext();
immediateContext->UpdateSubresource(resource, destSubresource,
&destD3DBox, conversionBuffer.data(), if (!fullUpdate)
bufferRowPitch, bufferDepthPitch); {
ASSERT(destBox);
D3D11_BOX destD3DBox;
destD3DBox.left = destBox->x;
destD3DBox.right = destBox->x + destBox->width;
destD3DBox.top = destBox->y;
destD3DBox.bottom = destBox->y + destBox->height;
destD3DBox.front = 0;
destD3DBox.back = 1;
immediateContext->UpdateSubresource(resource, destSubresource,
&destD3DBox, conversionBuffer.data(),
bufferRowPitch, bufferDepthPitch);
}
else
{
immediateContext->UpdateSubresource(resource, destSubresource,
NULL, conversionBuffer.data(),
bufferRowPitch, bufferDepthPitch);
}
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
......
...@@ -69,7 +69,7 @@ class TextureStorage11 : public TextureStorage ...@@ -69,7 +69,7 @@ class TextureStorage11 : public TextureStorage
virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) = 0; virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) = 0;
virtual gl::Error copyToStorage(TextureStorage *destStorage); virtual gl::Error copyToStorage(TextureStorage *destStorage);
virtual gl::Error setData(const gl::ImageIndex &index, const gl::Box &sourceBox, GLenum internalFormat, GLenum type, virtual gl::Error setData(const gl::ImageIndex &index, Image *image, const gl::Box *destBox, GLenum type,
const gl::PixelUnpackState &unpack, const uint8_t *pixelData); const gl::PixelUnpackState &unpack, const uint8_t *pixelData);
protected: protected:
......
...@@ -87,7 +87,7 @@ int TextureStorage9::getLevelCount() const ...@@ -87,7 +87,7 @@ int TextureStorage9::getLevelCount() const
return getBaseTexture() ? (getBaseTexture()->GetLevelCount() - getTopLevel()) : 0; return getBaseTexture() ? (getBaseTexture()->GetLevelCount() - getTopLevel()) : 0;
} }
gl::Error TextureStorage9::setData(const gl::ImageIndex &index, const gl::Box &sourceBox, GLenum internalFormat, GLenum type, gl::Error TextureStorage9::setData(const gl::ImageIndex &index, Image *image, const gl::Box *destBox, GLenum type,
const gl::PixelUnpackState &unpack, const uint8_t *pixelData) const gl::PixelUnpackState &unpack, const uint8_t *pixelData)
{ {
UNREACHABLE(); UNREACHABLE();
......
...@@ -42,7 +42,7 @@ class TextureStorage9 : public TextureStorage ...@@ -42,7 +42,7 @@ class TextureStorage9 : public TextureStorage
virtual bool isManaged() const; virtual bool isManaged() const;
virtual int getLevelCount() const; virtual int getLevelCount() const;
virtual gl::Error setData(const gl::ImageIndex &index, const gl::Box &sourceBox, GLenum internalFormat, GLenum type, virtual gl::Error setData(const gl::ImageIndex &index, Image *image, const gl::Box *destBox, GLenum type,
const gl::PixelUnpackState &unpack, const uint8_t *pixelData); const gl::PixelUnpackState &unpack, const uint8_t *pixelData);
protected: protected:
......
...@@ -36,6 +36,17 @@ ...@@ -36,6 +36,17 @@
EXPECT_EQ((a), pixel[3]); \ EXPECT_EQ((a), pixel[3]); \
} }
#define EXPECT_PIXEL_NEAR(x, y, r, g, b, a, abs_error) \
{ \
GLubyte pixel[4]; \
glReadPixels((x), (y), 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel); \
EXPECT_GL_NO_ERROR(); \
EXPECT_NEAR((r), pixel[0], abs_error); \
EXPECT_NEAR((g), pixel[1], abs_error); \
EXPECT_NEAR((b), pixel[2], abs_error); \
EXPECT_NEAR((a), pixel[3], abs_error); \
}
class EGLWindow; class EGLWindow;
class OSWindow; class OSWindow;
......
...@@ -4,11 +4,14 @@ ...@@ -4,11 +4,14 @@
typedef ::testing::Types<TFT<Gles::Two, Rend::D3D11>, TFT<Gles::Two, Rend::D3D9>> TestFixtureTypes; typedef ::testing::Types<TFT<Gles::Two, Rend::D3D11>, TFT<Gles::Two, Rend::D3D9>> TestFixtureTypes;
TYPED_TEST_CASE(DepthStencilFormatsTest, TestFixtureTypes); TYPED_TEST_CASE(DepthStencilFormatsTest, TestFixtureTypes);
typedef ::testing::Types<TFT<Gles::Three, Rend::D3D11>> TestFixtureTypesES3;
TYPED_TEST_CASE(DepthStencilFormatsTestES3, TestFixtureTypesES3);
template<typename T> template<typename T>
class DepthStencilFormatsTest : public ANGLETest class DepthStencilFormatsTestBase : public ANGLETest
{ {
protected: protected:
DepthStencilFormatsTest() : ANGLETest(T::GetGlesMajorVersion(), T::GetRequestedRenderer()) DepthStencilFormatsTestBase() : ANGLETest(T::GetGlesMajorVersion(), T::GetRequestedRenderer())
{ {
setWindowWidth(128); setWindowWidth(128);
setWindowHeight(128); setWindowHeight(128);
...@@ -60,14 +63,66 @@ protected: ...@@ -60,14 +63,66 @@ protected:
virtual void SetUp() virtual void SetUp()
{ {
ANGLETest::SetUp(); ANGLETest::SetUp();
const std::string vertexShaderSource = SHADER_SOURCE
(
precision highp float;
attribute vec4 position;
varying vec2 texcoord;
void main()
{
gl_Position = position;
texcoord = (position.xy * 0.5) + 0.5;
}
);
const std::string fragmentShaderSource = SHADER_SOURCE
(
precision highp float;
uniform sampler2D tex;
varying vec2 texcoord;
void main()
{
gl_FragColor = texture2D(tex, texcoord);
}
);
mProgram = CompileProgram(vertexShaderSource, fragmentShaderSource);
if (mProgram == 0)
{
FAIL() << "shader compilation failed.";
}
mTextureUniformLocation = glGetUniformLocation(mProgram, "tex");
EXPECT_NE(-1, mTextureUniformLocation);
glGenTextures(1, &mTexture);
ASSERT_GL_NO_ERROR();
} }
virtual void TearDown() virtual void TearDown()
{ {
glDeleteProgram(mProgram);
glDeleteTextures(1, &mTexture);
ANGLETest::TearDown(); ANGLETest::TearDown();
} }
GLuint mProgram;
GLuint mTexture;
GLint mTextureUniformLocation;
}; };
template <typename T>
class DepthStencilFormatsTest : public DepthStencilFormatsTestBase<T>
{};
template <typename T>
class DepthStencilFormatsTestES3 : public DepthStencilFormatsTestBase<T>
{};
TYPED_TEST(DepthStencilFormatsTest, DepthTexture) TYPED_TEST(DepthStencilFormatsTest, DepthTexture)
{ {
bool shouldHaveTextureSupport = extensionEnabled("GL_ANGLE_depth_texture"); bool shouldHaveTextureSupport = extensionEnabled("GL_ANGLE_depth_texture");
...@@ -98,3 +153,28 @@ TYPED_TEST(DepthStencilFormatsTest, PackedDepthStencil) ...@@ -98,3 +153,28 @@ TYPED_TEST(DepthStencilFormatsTest, PackedDepthStencil)
EXPECT_EQ(shouldHaveTextureSupport, checkTexStorageFormatSupport(GL_DEPTH24_STENCIL8_OES)); EXPECT_EQ(shouldHaveTextureSupport, checkTexStorageFormatSupport(GL_DEPTH24_STENCIL8_OES));
} }
} }
TYPED_TEST(DepthStencilFormatsTestES3, DrawWithDepthStencil)
{
GLushort data[16];
for (unsigned int i = 0; i < 16; i++)
{
data[i] = std::numeric_limits<GLushort>::max();
}
glBindTexture(GL_TEXTURE_2D, mTexture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH_COMPONENT16, 4, 4);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glUseProgram(mProgram);
glUniform1i(mTextureUniformLocation, 0);
glClear(GL_COLOR_BUFFER_BIT);
drawQuad(mProgram, "position", 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_NEAR(0, 0, 255, 0, 0, 255, 2.0);
}
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