Commit a42a4e5e by Jamie Madill Committed by Commit Bot

D3D11: Copy external offscreen texture when required.

In some cases ANGLE gets an external back buffer texture for our SwapChain11 class, and in some of these cases we get an offscreen texture that can't be used as a shader resource. The becomes a problem for some copy operations that use a shader to convert texture formats. Work around this problem by making a shadow copy of the texture that has sampling enabled - it is possible to use CopyResource to copy between them. BUG=chromium:752917 Change-Id: Ib757949d3d06295a118b055bf37311f820f7149c Reviewed-on: https://chromium-review.googlesource.com/638551Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 16daadba
......@@ -224,6 +224,14 @@ EGLint SwapChain11::resetOffscreenColorBuffer(const gl::Context *context,
}
ASSERT(mOffscreenTexture.valid());
mOffscreenTexture.getDesc(&offscreenTextureDesc);
// Fail if the offscreen texture is not renderable.
if ((offscreenTextureDesc.BindFlags & D3D11_BIND_RENDER_TARGET) == 0)
{
ERR() << "Could not use provided offscreen texture, texture not renderable.";
release();
return EGL_BAD_SURFACE;
}
}
else
{
......@@ -307,6 +315,23 @@ EGLint SwapChain11::resetOffscreenColorBuffer(const gl::Context *context,
ASSERT(!err.isError());
mOffscreenSRView.setDebugName("Offscreen back buffer shader resource");
}
else
{
// Special case for external textures that cannot support sampling. Since internally we
// assume our SwapChain is always readable, we make a copy texture that is compatible.
D3D11_TEXTURE2D_DESC offscreenCopyDesc = offscreenTextureDesc;
offscreenCopyDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
offscreenCopyDesc.MiscFlags = 0;
offscreenCopyDesc.CPUAccessFlags = 0;
err = mRenderer->allocateTexture(offscreenCopyDesc, backbufferFormatInfo,
&mOffscreenTextureCopyForSRV);
ASSERT(!err.isError());
mOffscreenTextureCopyForSRV.setDebugName("Offscreen back buffer copy for SRV");
err = mRenderer->allocateResource(offscreenSRVDesc, mOffscreenTextureCopyForSRV.get(),
&mOffscreenSRView);
ASSERT(!err.isError());
mOffscreenSRView.setDebugName("Offscreen back buffer shader resource");
}
if (previousOffscreenTexture.valid())
{
......@@ -928,7 +953,24 @@ const d3d11::RenderTargetView &SwapChain11::getRenderTarget()
const d3d11::SharedSRV &SwapChain11::getRenderTargetShaderResource()
{
return mNeedsOffscreenTexture ? mOffscreenSRView : mBackBufferSRView;
if (!mNeedsOffscreenTexture)
{
ASSERT(mBackBufferSRView.valid());
return mBackBufferSRView;
}
if (!mOffscreenTextureCopyForSRV.valid())
{
ASSERT(mOffscreenSRView.valid());
return mOffscreenSRView;
}
// Need to copy the offscreen texture into the shader-readable copy, since it's external and
// we don't know if the copy is up-to-date. This works around the problem we have when the app
// passes in a texture that isn't shader-readable.
mRenderer->getDeviceContext()->CopyResource(mOffscreenTextureCopyForSRV.get(),
mOffscreenTexture.get());
return mOffscreenSRView;
}
const d3d11::DepthStencilView &SwapChain11::getDepthStencil()
......
......@@ -110,6 +110,7 @@ class SwapChain11 final : public SwapChainD3D
TextureHelper11 mOffscreenTexture;
d3d11::RenderTargetView mOffscreenRTView;
d3d11::SharedSRV mOffscreenSRView;
TextureHelper11 mOffscreenTextureCopyForSRV;
TextureHelper11 mDepthStencilTexture;
d3d11::DepthStencilView mDepthStencilDSView;
......
......@@ -152,12 +152,13 @@ class D3DTextureTest : public ANGLETest
ANGLETest::TearDown();
}
EGLSurface createPBuffer(size_t width,
size_t height,
EGLint eglTextureFormat,
EGLint eglTextureTarget,
UINT sampleCount,
UINT sampleQuality)
EGLSurface createD3D11PBuffer(size_t width,
size_t height,
EGLint eglTextureFormat,
EGLint eglTextureTarget,
UINT sampleCount,
UINT sampleQuality,
UINT bindFlags)
{
EGLWindow *window = getEGLWindow();
EGLDisplay display = window->getDisplay();
......@@ -168,25 +169,47 @@ class D3DTextureTest : public ANGLETest
eglTextureTarget, EGL_NONE, EGL_NONE,
};
if (mD3D11Device)
{
ID3D11Texture2D *texture = nullptr;
CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_R8G8B8A8_UNORM, static_cast<UINT>(width),
static_cast<UINT>(height), 1, 1,
D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
desc.SampleDesc.Count = sampleCount;
desc.SampleDesc.Quality = sampleQuality;
EXPECT_TRUE(SUCCEEDED(mD3D11Device->CreateTexture2D(&desc, nullptr, &texture)));
ASSERT(mD3D11Device);
ID3D11Texture2D *texture = nullptr;
CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_R8G8B8A8_UNORM, static_cast<UINT>(width),
static_cast<UINT>(height), 1, 1, bindFlags);
desc.SampleDesc.Count = sampleCount;
desc.SampleDesc.Quality = sampleQuality;
EXPECT_TRUE(SUCCEEDED(mD3D11Device->CreateTexture2D(&desc, nullptr, &texture)));
EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(display, EGL_D3D_TEXTURE_ANGLE,
texture, config, attribs);
EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(display, EGL_D3D_TEXTURE_ANGLE,
texture, config, attribs);
texture->Release();
texture->Release();
return pbuffer;
return pbuffer;
}
EGLSurface createPBuffer(size_t width,
size_t height,
EGLint eglTextureFormat,
EGLint eglTextureTarget,
UINT sampleCount,
UINT sampleQuality)
{
if (mD3D11Device)
{
return createD3D11PBuffer(width, height, eglTextureFormat, eglTextureTarget,
sampleCount, sampleQuality,
D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
}
else if (mD3D9Device)
if (mD3D9Device)
{
EGLWindow *window = getEGLWindow();
EGLDisplay display = window->getDisplay();
EGLConfig config = window->getConfig();
EGLint attribs[] = {
EGL_TEXTURE_FORMAT, eglTextureFormat, EGL_TEXTURE_TARGET,
eglTextureTarget, EGL_NONE, EGL_NONE,
};
// Multisampled textures are not supported on D3D9.
ASSERT(sampleCount <= 1);
ASSERT(sampleQuality == 0);
......@@ -427,6 +450,56 @@ TEST_P(D3DTextureTest, CheckSampleMismatch)
EXPECT_EQ(pbuffer, nullptr);
}
// Tests what happens when we make a PBuffer that isn't shader-readable.
TEST_P(D3DTextureTest, NonReadablePBuffer)
{
ANGLE_SKIP_TEST_IF(!valid() || !IsD3D11());
constexpr size_t bufferSize = 32;
EGLSurface pbuffer = createD3D11PBuffer(bufferSize, bufferSize, EGL_TEXTURE_RGBA,
EGL_TEXTURE_2D, 1, 0, D3D11_BIND_RENDER_TARGET);
ASSERT_EGL_SUCCESS();
ASSERT_NE(pbuffer, EGL_NO_SURFACE);
EGLWindow *window = getEGLWindow();
EGLDisplay display = window->getDisplay();
eglMakeCurrent(display, pbuffer, pbuffer, window->getContext());
ASSERT_EGL_SUCCESS();
glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize));
// Clear to green.
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
// Copy the green color to a texture.
GLTexture tex;
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, bufferSize, bufferSize, 0);
ASSERT_GL_NO_ERROR();
// Clear to red.
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
// Draw with the texture and expect green.
draw2DTexturedQuad("position", 0.5f, 1.0f, false);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
// Make current with fixture EGL to ensure the Surface can be released immediately.
getEGLWindow()->makeCurrent();
eglDestroySurface(display, pbuffer);
}
class D3DTextureTestMS : public D3DTextureTest
{
protected:
......
......@@ -199,6 +199,7 @@ ANGLETestBase::ANGLETestBase(const angle::PlatformParameters &params)
mIgnoreD3D11SDKLayersWarnings(false),
mQuadVertexBuffer(0),
mQuadIndexBuffer(0),
m2DTexturedQuadProgram(0),
mDeferContextInit(false)
{
mEGLWindow = new EGLWindow(params.majorVersion, params.minorVersion, params.eglParameters);
......@@ -233,6 +234,10 @@ ANGLETestBase::~ANGLETestBase()
{
glDeleteBuffers(1, &mQuadIndexBuffer);
}
if (m2DTexturedQuadProgram)
{
glDeleteProgram(m2DTexturedQuadProgram);
}
SafeDelete(mEGLWindow);
}
......@@ -551,6 +556,44 @@ void ANGLETestBase::drawIndexedQuad(GLuint program,
}
}
GLuint ANGLETestBase::get2DTexturedQuadProgram()
{
if (m2DTexturedQuadProgram)
{
return m2DTexturedQuadProgram;
}
const std::string &vs =
"attribute vec2 position;\n"
"varying mediump vec2 texCoord;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(position, 0, 1);\n"
" texCoord = position * 0.5 + vec2(0.5);\n"
"}\n";
const std::string &fs =
"varying mediump vec2 texCoord;\n"
"uniform sampler2D tex;\n"
"void main()\n"
"{\n"
" gl_FragColor = texture2D(tex, texCoord);\n"
"}\n";
m2DTexturedQuadProgram = CompileProgram(vs, fs);
return m2DTexturedQuadProgram;
}
void ANGLETestBase::draw2DTexturedQuad(const std::string &positionAttribName,
GLfloat positionAttribZ,
GLfloat positionAttribXYScale,
bool useVertexBuffer)
{
ASSERT_NE(0u, get2DTexturedQuadProgram());
return drawQuad(get2DTexturedQuadProgram(), positionAttribName, positionAttribZ,
positionAttribXYScale, useVertexBuffer);
}
GLuint ANGLETestBase::compileShader(GLenum type, const std::string &source)
{
GLuint shader = glCreateShader(type);
......
......@@ -278,6 +278,11 @@ class ANGLETestBase
bool useBufferObject,
bool restrictedRange);
void draw2DTexturedQuad(const std::string &positionAttribName,
GLfloat positionAttribZ,
GLfloat positionAttribXYScale,
bool useVertexBuffer);
static GLuint compileShader(GLenum type, const std::string &source);
static bool extensionEnabled(const std::string &extName);
static bool extensionRequestable(const std::string &extName);
......@@ -328,6 +333,8 @@ class ANGLETestBase
void checkD3D11SDKLayersMessages();
GLuint get2DTexturedQuadProgram();
EGLWindow *mEGLWindow;
int mWidth;
int mHeight;
......@@ -338,6 +345,9 @@ class ANGLETestBase
GLuint mQuadVertexBuffer;
GLuint mQuadIndexBuffer;
// Used for texture rendering.
GLuint m2DTexturedQuadProgram;
TestPlatformContext mPlatformContext;
bool mDeferContextInit;
......
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