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/222911
Tested-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
This commit is contained in:
Jamie Madill 2014-10-20 10:59:56 -04:00
Родитель 24e8319263
Коммит ec6de4ec53
11 изменённых файлов: 177 добавлений и 39 удалений

Просмотреть файл

@ -194,4 +194,15 @@ bool VertexFormat::operator<(const VertexFormat& other) const
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
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) { }
bool operator==(const Box &other) const;
bool operator!=(const Box &other) const;
};
struct Extents

Просмотреть файл

@ -90,9 +90,30 @@ GLenum TextureD3D::getBaseLevelInternalFormat() const
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)
{
Image *image = getImage(index);
ASSERT(image);
// No-op
if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
@ -123,13 +144,9 @@ gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type,
{
gl::Error error(GL_NO_ERROR);
gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat());
// TODO(jmadill): Handle compressed internal formats
if (mTexStorage && mRenderer->getWorkarounds().setDataFasterThanImageUpload && !internalFormat.compressed)
if (shouldUseSetData(image))
{
gl::Box sourceBox(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth());
error = mTexStorage->setData(index, sourceBox, image->getInternalFormat(), type, unpack, pixelData);
error = mTexStorage->setData(index, image, NULL, type, unpack, pixelData);
}
else
{
@ -168,14 +185,10 @@ gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsi
Image *image = getImage(index);
ASSERT(image);
gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat());
gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
// TODO(jmadill): Handle compressed internal formats
if (mTexStorage && mRenderer->getWorkarounds().setDataFasterThanImageUpload && !internalFormat.compressed)
if (shouldUseSetData(image))
{
return mTexStorage->setData(index, region, image->getInternalFormat(),
type, unpack, pixelData);
return mTexStorage->setData(index, image, &region, type, unpack, pixelData);
}
gl::Error error = image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment,

Просмотреть файл

@ -99,6 +99,8 @@ class TextureD3D : public TextureImpl
virtual gl::Error initializeStorage(bool renderTarget) = 0;
virtual gl::Error updateStorage() = 0;
bool shouldUseSetData(const Image *image) const;
};
class TextureD3D_2D : public TextureD3D

Просмотреть файл

@ -27,6 +27,7 @@ namespace rx
class Renderer;
class SwapChain;
class RenderTarget;
class Image;
class TextureStorage
{
@ -43,7 +44,7 @@ class TextureStorage
virtual void generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) = 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;
unsigned int getRenderTargetSerial(const gl::ImageIndex &index) const;

Просмотреть файл

@ -422,7 +422,7 @@ gl::Error TextureStorage11::copyToStorage(TextureStorage *destStorage)
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)
{
ID3D11Resource *resource = getResource();
@ -430,7 +430,10 @@ gl::Error TextureStorage11::setData(const gl::ImageIndex &index, const gl::Box &
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
// 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 &
// with compressed formats in the calling logic.
ASSERT(!internalFormatInfo.compressed);
UINT srcRowPitch = internalFormatInfo.computeRowPitch(type, destBox.width, unpack.alignment);
UINT srcDepthPitch = internalFormatInfo.computeDepthPitch(type, destBox.width, destBox.height, unpack.alignment);
int width = destBox ? destBox->width : static_cast<int>(image->getWidth());
int height = destBox ? destBox->height : static_cast<int>(image->getHeight());
int depth = destBox ? destBox->depth : static_cast<int>(image->getDepth());
UINT srcRowPitch = internalFormatInfo.computeRowPitch(type, width, unpack.alignment);
UINT srcDepthPitch = internalFormatInfo.computeDepthPitch(type, width, height, unpack.alignment);
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;
const d3d11::TextureFormat &d3d11Format = d3d11::GetTextureFormatInfo(internalFormat);
const d3d11::TextureFormat &d3d11Format = d3d11::GetTextureFormatInfo(image->getInternalFormat());
const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(d3d11Format.texFormat);
size_t outputPixelSize = dxgiFormatInfo.pixelBytes;
UINT bufferRowPitch = outputPixelSize * destBox.width;
UINT bufferDepthPitch = bufferRowPitch * destBox.height;
UINT bufferRowPitch = outputPixelSize * width;
UINT bufferDepthPitch = bufferRowPitch * height;
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.");
}
// TODO: fast path
LoadImageFunction loadFunction = d3d11Format.loadFunctions.at(type);
loadFunction(destBox.width, destBox.height, destBox.depth,
loadFunction(width, height, depth,
pixelData, srcRowPitch, srcDepthPitch,
conversionBuffer.data(), bufferRowPitch, bufferDepthPitch);
ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext();
immediateContext->UpdateSubresource(resource, destSubresource,
&destD3DBox, conversionBuffer.data(),
bufferRowPitch, bufferDepthPitch);
if (!fullUpdate)
{
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);
}

Просмотреть файл

@ -69,7 +69,7 @@ class TextureStorage11 : public TextureStorage
virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) = 0;
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);
protected:

Просмотреть файл

@ -87,7 +87,7 @@ int TextureStorage9::getLevelCount() const
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)
{
UNREACHABLE();

Просмотреть файл

@ -42,7 +42,7 @@ class TextureStorage9 : public TextureStorage
virtual bool isManaged() 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);
protected:

Просмотреть файл

@ -36,6 +36,17 @@
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 OSWindow;

Просмотреть файл

@ -4,11 +4,14 @@
typedef ::testing::Types<TFT<Gles::Two, Rend::D3D11>, TFT<Gles::Two, Rend::D3D9>> TestFixtureTypes;
TYPED_TEST_CASE(DepthStencilFormatsTest, TestFixtureTypes);
typedef ::testing::Types<TFT<Gles::Three, Rend::D3D11>> TestFixtureTypesES3;
TYPED_TEST_CASE(DepthStencilFormatsTestES3, TestFixtureTypesES3);
template<typename T>
class DepthStencilFormatsTest : public ANGLETest
class DepthStencilFormatsTestBase : public ANGLETest
{
protected:
DepthStencilFormatsTest() : ANGLETest(T::GetGlesMajorVersion(), T::GetRequestedRenderer())
protected:
DepthStencilFormatsTestBase() : ANGLETest(T::GetGlesMajorVersion(), T::GetRequestedRenderer())
{
setWindowWidth(128);
setWindowHeight(128);
@ -60,14 +63,66 @@ protected:
virtual void 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()
{
glDeleteProgram(mProgram);
glDeleteTextures(1, &mTexture);
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)
{
bool shouldHaveTextureSupport = extensionEnabled("GL_ANGLE_depth_texture");
@ -98,3 +153,28 @@ TYPED_TEST(DepthStencilFormatsTest, PackedDepthStencil)
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);
}