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)
egl.restrictions for acceptable texture object types and formats.
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
object must have been created by the same D3D11 device queried from the
......@@ -202,9 +203,10 @@ Issues
RESOLVED: The texture offsets specified by EGL_TEXTURE_OFFSET_X_ANGLE and
EGL_TEXTURE_OFFSET_Y_ANGLE affect only rendering into the surface.
Specifically these affect the internal D3D viewport and scissor rect states.
This is needed to apply the update offset returned by calling BeginDraw() on
IDCompositionSurface, and is needed for correct rendering in that case.
Specifically these affect the internal D3D viewport and scissor rect states
for draws, clears, and blits. This is needed to apply the update offset
returned by calling BeginDraw() on IDCompositionSurface, and is needed for
correct rendering in that case.
Revision History
......
......@@ -803,6 +803,8 @@ Framebuffer::Framebuffer(const Context *context, egl::Surface *surface, egl::Sur
}
SetComponentTypeMask(getDrawbufferWriteType(0), 0, &mState.mDrawBufferTypeMask);
mState.mSurfaceTextureOffset = surface->getTextureOffset();
// Ensure the backend has a chance to synchronize its content for a new backbuffer.
mDirtyBits.set(DIRTY_BIT_COLOR_BUFFER_CONTENTS_0);
}
......@@ -1725,13 +1727,9 @@ bool Framebuffer::hasValidDepthStencil() const
return mState.getDepthStencilAttachment() != nullptr;
}
gl::Offset Framebuffer::getTextureOffset() const
const gl::Offset &Framebuffer::getSurfaceTextureOffset() const
{
if (isDefault() && getFirstColorAttachment()->getSurface())
{
return getFirstColorAttachment()->getSurface()->getTextureOffset();
}
return gl::Offset();
return mState.getSurfaceTextureOffset();
}
void Framebuffer::setAttachment(const Context *context,
......
......@@ -129,6 +129,8 @@ class FramebufferState final : angle::NonCopyable
return mDepthBufferFeedbackLoop || mStencilBufferFeedbackLoop;
}
const gl::Offset &getSurfaceTextureOffset() const { return mSurfaceTextureOffset; }
private:
const FramebufferAttachment *getWebGLDepthStencilAttachment() const;
const FramebufferAttachment *getWebGLDepthAttachment() const;
......@@ -177,6 +179,8 @@ class FramebufferState final : angle::NonCopyable
bool mDefaultFramebufferReadAttachmentInitialized;
FramebufferAttachment mDefaultFramebufferReadAttachment;
gl::Offset mSurfaceTextureOffset;
};
class Framebuffer final : public angle::ObserverInterface,
......@@ -315,9 +319,9 @@ class Framebuffer final : public angle::ObserverInterface,
bool hasValidDepthStencil() const;
// 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
// all rendering.
gl::Offset getTextureOffset() const;
// zero offset otherwise. The renderer will apply the offset to scissor and viewport rects used
// for draws, clears, and blits.
const gl::Offset &getSurfaceTextureOffset() const;
angle::Result discard(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)
clearParams.clearStencil = false;
clearParams.stencilValue = state.getStencilClearValue();
clearParams.stencilWriteMask = state.getDepthStencilState().stencilWritemask;
clearParams.scissorEnabled = state.isScissorTestEnabled();
clearParams.scissor = state.getScissor();
const gl::Framebuffer *framebufferObject = state.getDrawFramebuffer();
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.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 bool clearColor =
(mask & GL_COLOR_BUFFER_BIT) && framebufferObject->hasEnabledDrawBuffer();
if (clearColor)
......
......@@ -318,6 +318,11 @@ angle::Result Framebuffer11::blitImpl(const gl::Context *context,
const bool invertColorDest = UsePresentPathFast(mRenderer, &drawBuffer);
gl::Rectangle actualDestArea = destArea;
const auto &surfaceTextureOffset = mState.getSurfaceTextureOffset();
actualDestArea.x = actualDestArea.x + surfaceTextureOffset.x;
actualDestArea.y = actualDestArea.y + surfaceTextureOffset.y;
if (invertColorDest)
{
RenderTarget11 *drawRenderTarget11 = GetAs<RenderTarget11>(drawRenderTarget);
......
......@@ -1378,7 +1378,7 @@ void StateManager11::syncScissorRectangle(const gl::Context *context)
const gl::Rectangle &scissor = glState.getScissor();
const bool enabled = glState.isScissorTestEnabled();
mCurScissorOffset = framebuffer->getTextureOffset();
mCurScissorOffset = framebuffer->getSurfaceTextureOffset();
int scissorX = scissor.x + mCurScissorOffset.x;
int scissorY = scissor.y + mCurScissorOffset.y;
......@@ -1435,7 +1435,7 @@ void StateManager11::syncViewport(const gl::Context *context)
int dxViewportWidth = 0;
int dxViewportHeight = 0;
mCurViewportOffset = framebuffer->getTextureOffset();
mCurViewportOffset = framebuffer->getSurfaceTextureOffset();
dxViewportTopLeftX =
gl::clamp(viewport.x + mCurViewportOffset.x, dxMinViewportBoundsX, dxMaxViewportBoundsX);
......@@ -1521,11 +1521,11 @@ void StateManager11::processFramebufferInvalidation(const gl::Context *context)
ASSERT(fbo);
// 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);
}
if (mCurScissorOffset != fbo->getTextureOffset())
if (mCurScissorOffset != fbo->getSurfaceTextureOffset())
{
mInternalDirtyBits.set(DIRTY_BIT_SCISSOR_STATE);
}
......
......@@ -1863,6 +1863,10 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display,
{
return EglBadAttribute() << "<buftype> doesn't support setting texture offset";
}
if (value < 0)
{
return EglBadAttribute() << "Texture offset cannot be negative";
}
break;
default:
......
......@@ -11,6 +11,7 @@
#include <vector>
#include "common/Color.h"
#include "common/platform.h"
#include "test_utils/ANGLETest.h"
#include "util/EGLWindow.h"
......@@ -1135,7 +1136,17 @@ TEST_P(EGLSurfaceTestD3D11, CreateDirectCompositionSurface)
EGLConfig 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());
mPbufferSurface = eglCreatePbufferFromClientBuffer(mDisplay, EGL_D3D_TEXTURE_ANGLE, buffer,
......@@ -1155,6 +1166,136 @@ TEST_P(EGLSurfaceTestD3D11, CreateDirectCompositionSurface)
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)
{
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