Commit bc5d7add by Geoff Lang

D3D11: Clip copy rect to the source framebuffer for copyTexImage3D.

TEST=conformance2/textures/misc/copy-texture-image-webgl-specific.html BUG=angleproject:1815 Change-Id: I146fcf97a9c90f07d6270672c5e44e05602eecf8
parent 70c95fa6
...@@ -2575,7 +2575,18 @@ gl::Error TextureD3D_3D::copySubImage(const gl::Context *context, ...@@ -2575,7 +2575,18 @@ gl::Error TextureD3D_3D::copySubImage(const gl::Context *context,
{ {
ASSERT(target == GL_TEXTURE_3D); ASSERT(target == GL_TEXTURE_3D);
GLint level = static_cast<GLint>(imageLevel); GLint level = static_cast<GLint>(imageLevel);
gl::Extents fbSize = source->getReadColorbuffer()->getSize();
gl::Rectangle clippedSourceArea;
if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height),
&clippedSourceArea))
{
return gl::NoError();
}
const gl::Offset clippedDestOffset(destOffset.x + clippedSourceArea.x - sourceArea.x,
destOffset.y + clippedSourceArea.y - sourceArea.y,
destOffset.z);
// Currently, 3D single-layer blits are broken because we don't know how to make an SRV // Currently, 3D single-layer blits are broken because we don't know how to make an SRV
// for a single layer of a 3D texture. // for a single layer of a 3D texture.
...@@ -2584,7 +2595,8 @@ gl::Error TextureD3D_3D::copySubImage(const gl::Context *context, ...@@ -2584,7 +2595,8 @@ gl::Error TextureD3D_3D::copySubImage(const gl::Context *context,
// if (!canCreateRenderTargetForImage(index)) // if (!canCreateRenderTargetForImage(index))
{ {
ANGLE_TRY(mImageArray[level]->copyFromFramebuffer(context, destOffset, sourceArea, source)); ANGLE_TRY(mImageArray[level]->copyFromFramebuffer(context, clippedDestOffset,
clippedSourceArea, source));
mDirtyImages = true; mDirtyImages = true;
} }
// else // else
...@@ -3135,11 +3147,22 @@ gl::Error TextureD3D_2DArray::copySubImage(const gl::Context *context, ...@@ -3135,11 +3147,22 @@ gl::Error TextureD3D_2DArray::copySubImage(const gl::Context *context,
GLint level = static_cast<GLint>(imageLevel); GLint level = static_cast<GLint>(imageLevel);
gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, destOffset.z); gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, destOffset.z);
gl::Extents fbSize = source->getReadColorbuffer()->getSize();
gl::Rectangle clippedSourceArea;
if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height),
&clippedSourceArea))
{
return gl::NoError();
}
const gl::Offset clippedDestOffset(destOffset.x + clippedSourceArea.x - sourceArea.x,
destOffset.y + clippedSourceArea.y - sourceArea.y,
destOffset.z);
if (!canCreateRenderTargetForImage(index)) if (!canCreateRenderTargetForImage(index))
{ {
gl::Offset destLayerOffset(destOffset.x, destOffset.y, 0); gl::Offset destLayerOffset(clippedDestOffset.x, clippedDestOffset.y, 0);
ANGLE_TRY(mImageArray[level][destOffset.z]->copyFromFramebuffer(context, destLayerOffset, ANGLE_TRY(mImageArray[level][clippedDestOffset.z]->copyFromFramebuffer(
sourceArea, source)); context, destLayerOffset, clippedSourceArea, source));
mDirtyImages = true; mDirtyImages = true;
} }
else else
...@@ -3150,9 +3173,9 @@ gl::Error TextureD3D_2DArray::copySubImage(const gl::Context *context, ...@@ -3150,9 +3173,9 @@ gl::Error TextureD3D_2DArray::copySubImage(const gl::Context *context,
{ {
ANGLE_TRY(updateStorageLevel(context, level)); ANGLE_TRY(updateStorageLevel(context, level));
ANGLE_TRY( ANGLE_TRY(
mRenderer->copyImage2DArray(context, source, sourceArea, mRenderer->copyImage2DArray(context, source, clippedSourceArea,
gl::GetUnsizedFormat(getInternalFormat(getBaseLevel())), gl::GetUnsizedFormat(getInternalFormat(getBaseLevel())),
destOffset, mTexStorage, level)); clippedDestOffset, mTexStorage, level));
} }
} }
return gl::NoError(); return gl::NoError();
......
...@@ -49,6 +49,24 @@ class PixelRect ...@@ -49,6 +49,24 @@ class PixelRect
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
} }
void toTexture3D(GLuint texid, GLint depth) const
{
glBindTexture(GL_TEXTURE_3D, texid);
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, mWidth, mHeight, depth, 0, GL_RGBA,
GL_UNSIGNED_BYTE, nullptr);
for (GLint z = 0; z < depth; z++)
{
glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, z, mWidth, mHeight, 1, GL_RGBA,
GL_UNSIGNED_BYTE, mData.data());
}
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
}
void readFB(int x, int y) void readFB(int x, int y)
{ {
glReadPixels(x, y, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, mData.data()); glReadPixels(x, y, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, mData.data());
...@@ -83,8 +101,17 @@ class PixelRect ...@@ -83,8 +101,17 @@ class PixelRect
void compare(const PixelRect &expected) const void compare(const PixelRect &expected) const
{ {
for (int i = 0; i < mWidth * mHeight; ++i) ASSERT_EQ(mWidth, expected.mWidth);
ASSERT_EQ(expected.mData[i], mData[i]); ASSERT_EQ(mHeight, expected.mHeight);
for (int x = 0; x < mWidth; ++x)
{
for (int y = 0; y < mHeight; ++y)
{
ASSERT_EQ(expected.mData[x + y * mWidth], mData[x + y * mWidth])
<< "at (" << x << ", " << y << ")";
}
}
} }
private: private:
...@@ -101,10 +128,10 @@ class WebGLReadOutsideFramebufferTest : public ANGLETest ...@@ -101,10 +128,10 @@ class WebGLReadOutsideFramebufferTest : public ANGLETest
{ {
public: public:
// Read framebuffer to 'pixelsOut' via glReadPixels. // Read framebuffer to 'pixelsOut' via glReadPixels.
void TestReadPixels(int x, int y, PixelRect *pixelsOut) { pixelsOut->readFB(x, y); } void TestReadPixels(int x, int y, int, PixelRect *pixelsOut) { pixelsOut->readFB(x, y); }
// Read framebuffer to 'pixelsOut' via glCopyTexSubImage2D. // Read framebuffer to 'pixelsOut' via glCopyTexSubImage2D.
void TestCopyTexSubImage2D(int x, int y, PixelRect *pixelsOut) void TestCopyTexSubImage2D(int x, int y, int, PixelRect *pixelsOut)
{ {
// Init texture with given pixels. // Init texture with given pixels.
GLTexture destTexture; GLTexture destTexture;
...@@ -112,11 +139,23 @@ class WebGLReadOutsideFramebufferTest : public ANGLETest ...@@ -112,11 +139,23 @@ class WebGLReadOutsideFramebufferTest : public ANGLETest
// Read framebuffer -> texture -> 'pixelsOut' // Read framebuffer -> texture -> 'pixelsOut'
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, x, y, kReadWidth, kReadHeight); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, x, y, kReadWidth, kReadHeight);
readTexture(kReadWidth, kReadHeight, pixelsOut); readTexture2D(kReadWidth, kReadHeight, pixelsOut);
}
// Read framebuffer to 'pixelsOut' via glCopyTexSubImage3D.
void TestCopyTexSubImage3D(int x, int y, int z, PixelRect *pixelsOut)
{
// Init texture with given pixels.
GLTexture destTexture;
pixelsOut->toTexture3D(destTexture.get(), kTextureDepth);
// Read framebuffer -> texture -> 'pixelsOut'
glCopyTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, z, x, y, kReadWidth, kReadHeight);
readTexture3D(destTexture, kReadWidth, kReadHeight, z, pixelsOut);
} }
// Read framebuffer to 'pixelsOut' via glCopyTexImage2D. // Read framebuffer to 'pixelsOut' via glCopyTexImage2D.
void TestCopyTexImage2D(int x, int y, PixelRect *pixelsOut) void TestCopyTexImage2D(int x, int y, int, PixelRect *pixelsOut)
{ {
// Init texture with given pixels. // Init texture with given pixels.
GLTexture destTexture; GLTexture destTexture;
...@@ -124,14 +163,16 @@ class WebGLReadOutsideFramebufferTest : public ANGLETest ...@@ -124,14 +163,16 @@ class WebGLReadOutsideFramebufferTest : public ANGLETest
// Read framebuffer -> texture -> 'pixelsOut' // Read framebuffer -> texture -> 'pixelsOut'
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, kReadWidth, kReadHeight, 0); glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, kReadWidth, kReadHeight, 0);
readTexture(kReadWidth, kReadHeight, pixelsOut); readTexture2D(kReadWidth, kReadHeight, pixelsOut);
} }
protected: protected:
static constexpr int kFbWidth = 128; static constexpr int kFbWidth = 128;
static constexpr int kFbHeight = 128; static constexpr int kFbHeight = 128;
static constexpr int kTextureDepth = 16;
static constexpr int kReadWidth = 4; static constexpr int kReadWidth = 4;
static constexpr int kReadHeight = 4; static constexpr int kReadHeight = 4;
static constexpr int kReadLayer = 2;
// Tag the framebuffer pixels differently than the initial read buffer pixels, so we know for // Tag the framebuffer pixels differently than the initial read buffer pixels, so we know for
// sure which pixels are changed by reading. // sure which pixels are changed by reading.
...@@ -192,9 +233,19 @@ class WebGLReadOutsideFramebufferTest : public ANGLETest ...@@ -192,9 +233,19 @@ class WebGLReadOutsideFramebufferTest : public ANGLETest
ANGLETest::TearDown(); ANGLETest::TearDown();
} }
using TestFunc = void (WebGLReadOutsideFramebufferTest::*)(int x, int y, PixelRect *dest); using TestFunc = void (WebGLReadOutsideFramebufferTest::*)(int x,
int y,
int z,
PixelRect *dest);
void Main2D(TestFunc testFunc, bool zeroOutside) { mainImpl(testFunc, zeroOutside, 0); }
void Main3D(TestFunc testFunc, bool zeroOutside)
{
mainImpl(testFunc, zeroOutside, kReadLayer);
}
void Main(TestFunc testFunc, bool zeroOutside) void mainImpl(TestFunc testFunc, bool zeroOutside, int readLayer)
{ {
PixelRect actual(kReadWidth, kReadHeight); PixelRect actual(kReadWidth, kReadHeight);
PixelRect expected(kReadWidth, kReadHeight); PixelRect expected(kReadWidth, kReadHeight);
...@@ -216,7 +267,7 @@ class WebGLReadOutsideFramebufferTest : public ANGLETest ...@@ -216,7 +267,7 @@ class WebGLReadOutsideFramebufferTest : public ANGLETest
// Read from framebuffer into 'actual.' // Read from framebuffer into 'actual.'
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
(this->*testFunc)(x, y, &actual); (this->*testFunc)(x, y, readLayer, &actual);
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Simulate framebuffer read, into 'expected.' // Simulate framebuffer read, into 'expected.'
...@@ -230,7 +281,7 @@ class WebGLReadOutsideFramebufferTest : public ANGLETest ...@@ -230,7 +281,7 @@ class WebGLReadOutsideFramebufferTest : public ANGLETest
// Get contents of current texture by drawing it into a framebuffer then reading with // Get contents of current texture by drawing it into a framebuffer then reading with
// glReadPixels(). // glReadPixels().
void readTexture(GLsizei width, GLsizei height, PixelRect *out) void readTexture2D(GLsizei width, GLsizei height, PixelRect *out)
{ {
GLRenderbuffer colorBuffer; GLRenderbuffer colorBuffer;
glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer); glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer);
...@@ -246,17 +297,31 @@ class WebGLReadOutsideFramebufferTest : public ANGLETest ...@@ -246,17 +297,31 @@ class WebGLReadOutsideFramebufferTest : public ANGLETest
out->readFB(0, 0); out->readFB(0, 0);
} }
// Get contents of current texture by drawing it into a framebuffer then reading with
// glReadPixels().
void readTexture3D(GLuint texture, GLsizei width, GLsizei height, int zSlice, PixelRect *out)
{
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, zSlice);
out->readFB(0, 0);
}
PixelRect mFBData; PixelRect mFBData;
GLuint mProgram; GLuint mProgram;
}; };
class WebGL2ReadOutsideFramebufferTest : public WebGLReadOutsideFramebufferTest
{
};
// TODO(fjhenigman): Enable each test as part of a CL that lets the test pass. // TODO(fjhenigman): Enable each test as part of a CL that lets the test pass.
// Check that readPixels does not set a destination pixel when // Check that readPixels does not set a destination pixel when
// the corresponding source pixel is outside the framebuffer. // the corresponding source pixel is outside the framebuffer.
TEST_P(WebGLReadOutsideFramebufferTest, ReadPixels) TEST_P(WebGLReadOutsideFramebufferTest, ReadPixels)
{ {
Main(&WebGLReadOutsideFramebufferTest::TestReadPixels, false); Main2D(&WebGLReadOutsideFramebufferTest::TestReadPixels, false);
} }
// Check that copyTexSubImage2D does not set a destination pixel when // Check that copyTexSubImage2D does not set a destination pixel when
...@@ -270,7 +335,7 @@ TEST_P(WebGLReadOutsideFramebufferTest, CopyTexSubImage2D) ...@@ -270,7 +335,7 @@ TEST_P(WebGLReadOutsideFramebufferTest, CopyTexSubImage2D)
return; return;
} }
Main(&WebGLReadOutsideFramebufferTest::TestCopyTexSubImage2D, false); Main2D(&WebGLReadOutsideFramebufferTest::TestCopyTexSubImage2D, false);
} }
// Check that copyTexImage2D sets (0,0,0,0) for pixels outside the framebuffer. // Check that copyTexImage2D sets (0,0,0,0) for pixels outside the framebuffer.
...@@ -283,7 +348,21 @@ TEST_P(WebGLReadOutsideFramebufferTest, CopyTexImage2D) ...@@ -283,7 +348,21 @@ TEST_P(WebGLReadOutsideFramebufferTest, CopyTexImage2D)
return; return;
} }
Main(&WebGLReadOutsideFramebufferTest::TestCopyTexImage2D, true); Main2D(&WebGLReadOutsideFramebufferTest::TestCopyTexImage2D, true);
}
// Check that copyTexSubImage3D does not set a destination pixel when
// the corresponding source pixel is outside the framebuffer.
TEST_P(WebGL2ReadOutsideFramebufferTest, CopyTexSubImage3D)
{
if (IsDesktopOpenGL() || IsOpenGLES())
{
std::cout << "Robust CopyTexSubImage3D behaviour is not implemented on OpenGL."
<< std::endl;
return;
}
Main3D(&WebGLReadOutsideFramebufferTest::TestCopyTexSubImage3D, false);
} }
ANGLE_INSTANTIATE_TEST(WebGLReadOutsideFramebufferTest, ANGLE_INSTANTIATE_TEST(WebGLReadOutsideFramebufferTest,
...@@ -296,4 +375,10 @@ ANGLE_INSTANTIATE_TEST(WebGLReadOutsideFramebufferTest, ...@@ -296,4 +375,10 @@ ANGLE_INSTANTIATE_TEST(WebGLReadOutsideFramebufferTest,
ES2_OPENGLES(), ES2_OPENGLES(),
ES3_OPENGLES()); ES3_OPENGLES());
ANGLE_INSTANTIATE_TEST(WebGL2ReadOutsideFramebufferTest,
ES3_D3D11(),
ES3_OPENGL(),
ES2_OPENGLES(),
ES3_OPENGLES());
} // namespace } // namespace
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