Commit 3d5f0c82 by Sunny Sachanandani Committed by Commit Bot

Use surface texture offset for clears and blits

https://chromium-review.googlesource.com/c/angle/angle/+/2186176 added surface texture offset attributes for D3D11 pbuffer surfaces, but the implementation didn't apply the offset to blits or clears. This CL fixes that and includes a unit test for blit, clear, and draw. Also renames textureOffset to surfaceTextureOffset throughout since it's clearer, and fixes the dcomp surface test to specify the update offset returned by dcomp BeginDraw(). Bug: angleproject:2997 Change-Id: I9298ccf55cbb2d04c3b8f78e12f9d07dc8fa54b5 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2210967 Commit-Queue: Sunny Sachanandani <sunnyps@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 9dac86c9
...@@ -84,7 +84,8 @@ Additions to Chapter 2 of the EGL 1.2 Specification (EGL Operation) ...@@ -84,7 +84,8 @@ Additions to Chapter 2 of the EGL 1.2 Specification (EGL Operation)
egl.restrictions for acceptable texture object types and formats. egl.restrictions for acceptable texture object types and formats.
If EGL_TEXTURE_OFFSET_X_ANGLE or EGL_TEXTURE_OFFSET_Y_ANGLE are specified, If EGL_TEXTURE_OFFSET_X_ANGLE or EGL_TEXTURE_OFFSET_Y_ANGLE are specified,
they are used to offset all rendering into the surface. they must be non-negative and are used to offset all rendering into the
surface including blits, clears and draws.
If the EGL_ANGLE_device_d3d extension is present, the provided D3D11 texture If the EGL_ANGLE_device_d3d extension is present, the provided D3D11 texture
object must have been created by the same D3D11 device queried from the object must have been created by the same D3D11 device queried from the
...@@ -202,9 +203,10 @@ Issues ...@@ -202,9 +203,10 @@ Issues
RESOLVED: The texture offsets specified by EGL_TEXTURE_OFFSET_X_ANGLE and RESOLVED: The texture offsets specified by EGL_TEXTURE_OFFSET_X_ANGLE and
EGL_TEXTURE_OFFSET_Y_ANGLE affect only rendering into the surface. EGL_TEXTURE_OFFSET_Y_ANGLE affect only rendering into the surface.
Specifically these affect the internal D3D viewport and scissor rect states. Specifically these affect the internal D3D viewport and scissor rect states
This is needed to apply the update offset returned by calling BeginDraw() on for draws, clears, and blits. This is needed to apply the update offset
IDCompositionSurface, and is needed for correct rendering in that case. returned by calling BeginDraw() on IDCompositionSurface, and is needed for
correct rendering in that case.
Revision History Revision History
......
...@@ -803,6 +803,8 @@ Framebuffer::Framebuffer(const Context *context, egl::Surface *surface, egl::Sur ...@@ -803,6 +803,8 @@ Framebuffer::Framebuffer(const Context *context, egl::Surface *surface, egl::Sur
} }
SetComponentTypeMask(getDrawbufferWriteType(0), 0, &mState.mDrawBufferTypeMask); SetComponentTypeMask(getDrawbufferWriteType(0), 0, &mState.mDrawBufferTypeMask);
mState.mSurfaceTextureOffset = surface->getTextureOffset();
// Ensure the backend has a chance to synchronize its content for a new backbuffer. // Ensure the backend has a chance to synchronize its content for a new backbuffer.
mDirtyBits.set(DIRTY_BIT_COLOR_BUFFER_CONTENTS_0); mDirtyBits.set(DIRTY_BIT_COLOR_BUFFER_CONTENTS_0);
} }
...@@ -1725,13 +1727,9 @@ bool Framebuffer::hasValidDepthStencil() const ...@@ -1725,13 +1727,9 @@ bool Framebuffer::hasValidDepthStencil() const
return mState.getDepthStencilAttachment() != nullptr; return mState.getDepthStencilAttachment() != nullptr;
} }
gl::Offset Framebuffer::getTextureOffset() const const gl::Offset &Framebuffer::getSurfaceTextureOffset() const
{ {
if (isDefault() && getFirstColorAttachment()->getSurface()) return mState.getSurfaceTextureOffset();
{
return getFirstColorAttachment()->getSurface()->getTextureOffset();
}
return gl::Offset();
} }
void Framebuffer::setAttachment(const Context *context, void Framebuffer::setAttachment(const Context *context,
......
...@@ -129,6 +129,8 @@ class FramebufferState final : angle::NonCopyable ...@@ -129,6 +129,8 @@ class FramebufferState final : angle::NonCopyable
return mDepthBufferFeedbackLoop || mStencilBufferFeedbackLoop; return mDepthBufferFeedbackLoop || mStencilBufferFeedbackLoop;
} }
const gl::Offset &getSurfaceTextureOffset() const { return mSurfaceTextureOffset; }
private: private:
const FramebufferAttachment *getWebGLDepthStencilAttachment() const; const FramebufferAttachment *getWebGLDepthStencilAttachment() const;
const FramebufferAttachment *getWebGLDepthAttachment() const; const FramebufferAttachment *getWebGLDepthAttachment() const;
...@@ -177,6 +179,8 @@ class FramebufferState final : angle::NonCopyable ...@@ -177,6 +179,8 @@ class FramebufferState final : angle::NonCopyable
bool mDefaultFramebufferReadAttachmentInitialized; bool mDefaultFramebufferReadAttachmentInitialized;
FramebufferAttachment mDefaultFramebufferReadAttachment; FramebufferAttachment mDefaultFramebufferReadAttachment;
gl::Offset mSurfaceTextureOffset;
}; };
class Framebuffer final : public angle::ObserverInterface, class Framebuffer final : public angle::ObserverInterface,
...@@ -315,9 +319,9 @@ class Framebuffer final : public angle::ObserverInterface, ...@@ -315,9 +319,9 @@ class Framebuffer final : public angle::ObserverInterface,
bool hasValidDepthStencil() const; bool hasValidDepthStencil() const;
// Returns the offset into the texture backing the default framebuffer's surface if any. Returns // Returns the offset into the texture backing the default framebuffer's surface if any. Returns
// zero offset otherwise. Offset is applied to scissor and viewport rects so that it applies to // zero offset otherwise. The renderer will apply the offset to scissor and viewport rects used
// all rendering. // for draws, clears, and blits.
gl::Offset getTextureOffset() const; const gl::Offset &getSurfaceTextureOffset() const;
angle::Result discard(const Context *context, size_t count, const GLenum *attachments); angle::Result discard(const Context *context, size_t count, const GLenum *attachments);
angle::Result invalidate(const Context *context, size_t count, const GLenum *attachments); angle::Result invalidate(const Context *context, size_t count, const GLenum *attachments);
......
...@@ -41,10 +41,24 @@ ClearParameters GetClearParameters(const gl::State &state, GLbitfield mask) ...@@ -41,10 +41,24 @@ ClearParameters GetClearParameters(const gl::State &state, GLbitfield mask)
clearParams.clearStencil = false; clearParams.clearStencil = false;
clearParams.stencilValue = state.getStencilClearValue(); clearParams.stencilValue = state.getStencilClearValue();
clearParams.stencilWriteMask = state.getDepthStencilState().stencilWritemask; clearParams.stencilWriteMask = state.getDepthStencilState().stencilWritemask;
clearParams.scissorEnabled = state.isScissorTestEnabled();
const auto *framebufferObject = state.getDrawFramebuffer();
const gl::Extents &framebufferSize = framebufferObject->getFirstNonNullAttachment()->getSize();
const gl::Offset &surfaceTextureOffset = framebufferObject->getSurfaceTextureOffset();
if (state.isScissorTestEnabled())
{
clearParams.scissorEnabled = true;
clearParams.scissor = state.getScissor(); clearParams.scissor = state.getScissor();
clearParams.scissor.x = clearParams.scissor.x + surfaceTextureOffset.x;
clearParams.scissor.y = clearParams.scissor.y + surfaceTextureOffset.y;
}
else if (surfaceTextureOffset != gl::kOffsetZero)
{
clearParams.scissorEnabled = true;
clearParams.scissor = gl::Rectangle(surfaceTextureOffset.x, surfaceTextureOffset.y,
framebufferSize.width, framebufferSize.height);
}
const gl::Framebuffer *framebufferObject = state.getDrawFramebuffer();
const bool clearColor = const bool clearColor =
(mask & GL_COLOR_BUFFER_BIT) && framebufferObject->hasEnabledDrawBuffer(); (mask & GL_COLOR_BUFFER_BIT) && framebufferObject->hasEnabledDrawBuffer();
if (clearColor) if (clearColor)
......
...@@ -318,6 +318,11 @@ angle::Result Framebuffer11::blitImpl(const gl::Context *context, ...@@ -318,6 +318,11 @@ angle::Result Framebuffer11::blitImpl(const gl::Context *context,
const bool invertColorDest = UsePresentPathFast(mRenderer, &drawBuffer); const bool invertColorDest = UsePresentPathFast(mRenderer, &drawBuffer);
gl::Rectangle actualDestArea = destArea; gl::Rectangle actualDestArea = destArea;
const auto &surfaceTextureOffset = mState.getSurfaceTextureOffset();
actualDestArea.x = actualDestArea.x + surfaceTextureOffset.x;
actualDestArea.y = actualDestArea.y + surfaceTextureOffset.y;
if (invertColorDest) if (invertColorDest)
{ {
RenderTarget11 *drawRenderTarget11 = GetAs<RenderTarget11>(drawRenderTarget); RenderTarget11 *drawRenderTarget11 = GetAs<RenderTarget11>(drawRenderTarget);
......
...@@ -1378,7 +1378,7 @@ void StateManager11::syncScissorRectangle(const gl::Context *context) ...@@ -1378,7 +1378,7 @@ void StateManager11::syncScissorRectangle(const gl::Context *context)
const gl::Rectangle &scissor = glState.getScissor(); const gl::Rectangle &scissor = glState.getScissor();
const bool enabled = glState.isScissorTestEnabled(); const bool enabled = glState.isScissorTestEnabled();
mCurScissorOffset = framebuffer->getTextureOffset(); mCurScissorOffset = framebuffer->getSurfaceTextureOffset();
int scissorX = scissor.x + mCurScissorOffset.x; int scissorX = scissor.x + mCurScissorOffset.x;
int scissorY = scissor.y + mCurScissorOffset.y; int scissorY = scissor.y + mCurScissorOffset.y;
...@@ -1435,7 +1435,7 @@ void StateManager11::syncViewport(const gl::Context *context) ...@@ -1435,7 +1435,7 @@ void StateManager11::syncViewport(const gl::Context *context)
int dxViewportWidth = 0; int dxViewportWidth = 0;
int dxViewportHeight = 0; int dxViewportHeight = 0;
mCurViewportOffset = framebuffer->getTextureOffset(); mCurViewportOffset = framebuffer->getSurfaceTextureOffset();
dxViewportTopLeftX = dxViewportTopLeftX =
gl::clamp(viewport.x + mCurViewportOffset.x, dxMinViewportBoundsX, dxMaxViewportBoundsX); gl::clamp(viewport.x + mCurViewportOffset.x, dxMinViewportBoundsX, dxMaxViewportBoundsX);
...@@ -1521,11 +1521,11 @@ void StateManager11::processFramebufferInvalidation(const gl::Context *context) ...@@ -1521,11 +1521,11 @@ void StateManager11::processFramebufferInvalidation(const gl::Context *context)
ASSERT(fbo); ASSERT(fbo);
// Dirty scissor and viewport because surface texture offset might have changed. // Dirty scissor and viewport because surface texture offset might have changed.
if (mCurViewportOffset != fbo->getTextureOffset()) if (mCurViewportOffset != fbo->getSurfaceTextureOffset())
{ {
mInternalDirtyBits.set(DIRTY_BIT_VIEWPORT_STATE); mInternalDirtyBits.set(DIRTY_BIT_VIEWPORT_STATE);
} }
if (mCurScissorOffset != fbo->getTextureOffset()) if (mCurScissorOffset != fbo->getSurfaceTextureOffset())
{ {
mInternalDirtyBits.set(DIRTY_BIT_SCISSOR_STATE); mInternalDirtyBits.set(DIRTY_BIT_SCISSOR_STATE);
} }
......
...@@ -1863,6 +1863,10 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, ...@@ -1863,6 +1863,10 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display,
{ {
return EglBadAttribute() << "<buftype> doesn't support setting texture offset"; return EglBadAttribute() << "<buftype> doesn't support setting texture offset";
} }
if (value < 0)
{
return EglBadAttribute() << "Texture offset cannot be negative";
}
break; break;
default: default:
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <vector> #include <vector>
#include "common/Color.h"
#include "common/platform.h" #include "common/platform.h"
#include "test_utils/ANGLETest.h" #include "test_utils/ANGLETest.h"
#include "util/EGLWindow.h" #include "util/EGLWindow.h"
...@@ -1135,7 +1136,17 @@ TEST_P(EGLSurfaceTestD3D11, CreateDirectCompositionSurface) ...@@ -1135,7 +1136,17 @@ TEST_P(EGLSurfaceTestD3D11, CreateDirectCompositionSurface)
EGLConfig config; EGLConfig config;
ASSERT_EGL_TRUE(EGLWindow::FindEGLConfig(mDisplay, configAttributes, &config)); ASSERT_EGL_TRUE(EGLWindow::FindEGLConfig(mDisplay, configAttributes, &config));
const EGLint surfaceAttributes[] = {EGL_WIDTH, 64, EGL_HEIGHT, 64, EGL_NONE}; const EGLint surfaceAttributes[] = {EGL_WIDTH,
100,
EGL_HEIGHT,
100,
EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE,
EGL_TRUE,
EGL_TEXTURE_OFFSET_X_ANGLE,
updateOffset.x,
EGL_TEXTURE_OFFSET_Y_ANGLE,
updateOffset.y,
EGL_NONE};
EGLClientBuffer buffer = reinterpret_cast<EGLClientBuffer>(texture.Get()); EGLClientBuffer buffer = reinterpret_cast<EGLClientBuffer>(texture.Get());
mPbufferSurface = eglCreatePbufferFromClientBuffer(mDisplay, EGL_D3D_TEXTURE_ANGLE, buffer, mPbufferSurface = eglCreatePbufferFromClientBuffer(mDisplay, EGL_D3D_TEXTURE_ANGLE, buffer,
...@@ -1155,6 +1166,136 @@ TEST_P(EGLSurfaceTestD3D11, CreateDirectCompositionSurface) ...@@ -1155,6 +1166,136 @@ TEST_P(EGLSurfaceTestD3D11, CreateDirectCompositionSurface)
glDeleteProgram(program); glDeleteProgram(program);
} }
TEST_P(EGLSurfaceTestD3D11, CreateSurfaceWithTextureOffset)
{
ANGLE_SKIP_TEST_IF(!IsEGLClientExtensionEnabled("EGL_ANGLE_platform_angle_d3d"));
initializeDisplay();
const EGLint configAttributes[] = {
EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8,
EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 0, EGL_SAMPLE_BUFFERS, 0, EGL_NONE};
EGLConfig config;
ASSERT_EGL_TRUE(EGLWindow::FindEGLConfig(mDisplay, configAttributes, &config));
mConfig = config;
initializeContext();
EGLAttrib device = 0;
EGLAttrib newEglDevice = 0;
ASSERT_EGL_TRUE(eglQueryDisplayAttribEXT(mDisplay, EGL_DEVICE_EXT, &newEglDevice));
ASSERT_EGL_TRUE(eglQueryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(newEglDevice),
EGL_D3D11_DEVICE_ANGLE, &device));
angle::ComPtr<ID3D11Device> d3d11Device(reinterpret_cast<ID3D11Device *>(device));
ASSERT_TRUE(!!d3d11Device);
constexpr UINT kTextureWidth = 100;
constexpr UINT kTextureHeight = 100;
constexpr Color<uint8_t> kOpaqueBlack(0, 0, 0, 255);
std::vector<Color<uint8_t>> textureData(kTextureWidth * kTextureHeight, kOpaqueBlack);
D3D11_SUBRESOURCE_DATA initialData = {};
initialData.pSysMem = textureData.data();
initialData.SysMemPitch = kTextureWidth * sizeof(kOpaqueBlack);
D3D11_TEXTURE2D_DESC desc = {};
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
desc.Width = kTextureWidth;
desc.Height = kTextureHeight;
desc.ArraySize = 1;
desc.MipLevels = 1;
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_RENDER_TARGET;
angle::ComPtr<ID3D11Texture2D> texture;
HRESULT hr = d3d11Device->CreateTexture2D(&desc, &initialData, &texture);
ASSERT_TRUE(SUCCEEDED(hr));
angle::ComPtr<ID3D11DeviceContext> d3d11Context;
d3d11Device->GetImmediateContext(&d3d11Context);
// Specify a texture offset of (50, 50) when rendering to the pbuffer surface.
const EGLint surfaceAttributes[] = {EGL_WIDTH,
kTextureWidth,
EGL_HEIGHT,
kTextureHeight,
EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE,
EGL_TRUE,
EGL_TEXTURE_OFFSET_X_ANGLE,
50,
EGL_TEXTURE_OFFSET_Y_ANGLE,
50,
EGL_NONE};
EGLClientBuffer buffer = reinterpret_cast<EGLClientBuffer>(texture.Get());
mPbufferSurface = eglCreatePbufferFromClientBuffer(mDisplay, EGL_D3D_TEXTURE_ANGLE, buffer,
config, surfaceAttributes);
ASSERT_EGL_SUCCESS();
eglMakeCurrent(mDisplay, mPbufferSurface, mPbufferSurface, mContext);
ASSERT_EGL_SUCCESS();
// glClear should only clear subrect at offset (50, 50) without explicit scissor.
glClearColor(0, 0, 1, 1); // Blue
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_EQ(25, 25, 0, 0, 0, 255);
EXPECT_PIXEL_EQ(75, 75, 0, 0, 255, 255);
EXPECT_GL_NO_ERROR();
// Drawing with a shader should also update the same subrect only without explicit viewport.
GLuint program = createProgram(); // Red
ASSERT_NE(0u, program);
GLint positionLocation = glGetAttribLocation(program, angle::essl1_shaders::PositionAttrib());
glUseProgram(program);
const GLfloat vertices[] = {
-1.0f, 1.0f, 0.5f, -1.0f, -1.0f, 0.5f, 1.0f, -1.0f, 0.5f,
-1.0f, 1.0f, 0.5f, 1.0f, -1.0f, 0.5f, 1.0f, 1.0f, 0.5f,
};
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
glEnableVertexAttribArray(positionLocation);
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(positionLocation);
glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
EXPECT_PIXEL_EQ(25, 25, 0, 0, 0, 255);
EXPECT_PIXEL_EQ(75, 75, 255, 0, 0, 255);
EXPECT_GL_NO_ERROR();
glDeleteProgram(program);
EXPECT_GL_NO_ERROR();
// Blit framebuffer should also blit to the same subrect despite the dstX/Y arguments.
GLuint renderBuffer = 0;
glGenRenderbuffers(1u, &renderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 50, 50);
EXPECT_GL_NO_ERROR();
GLuint framebuffer = 0;
glGenFramebuffers(1u, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBuffer);
EXPECT_GL_NO_ERROR();
glClearColor(0, 1, 0, 1); // Green
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_EQ(25, 25, 0, 255, 0, 255);
EXPECT_GL_NO_ERROR();
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0u);
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
glBlitFramebuffer(0, 0, 50, 50, 0, 0, 50, 50, GL_COLOR_BUFFER_BIT, GL_NEAREST);
EXPECT_GL_NO_ERROR();
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0u);
EXPECT_PIXEL_EQ(25, 25, 0, 0, 0, 255);
EXPECT_PIXEL_EQ(75, 75, 0, 255, 0, 255);
EXPECT_GL_NO_ERROR();
glDeleteFramebuffers(1u, &framebuffer);
glDeleteRenderbuffers(1u, &renderBuffer);
EXPECT_GL_NO_ERROR();
}
TEST_P(EGLSurfaceTestD3D11, CreateSurfaceWithMSAA) TEST_P(EGLSurfaceTestD3D11, CreateSurfaceWithMSAA)
{ {
ANGLE_SKIP_TEST_IF(!IsEGLClientExtensionEnabled("EGL_ANGLE_platform_angle_d3d")); ANGLE_SKIP_TEST_IF(!IsEGLClientExtensionEnabled("EGL_ANGLE_platform_angle_d3d"));
......
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