зеркало из https://github.com/AvaloniaUI/angle.git
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:
Родитель
24e8319263
Коммит
ec6de4ec53
|
@ -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, ®ion, 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);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче