Re-land "Implement EGL_experimental_present_path_angle"
- Re-land with clang fix.
This allows ANGLE to render directly onto a D3D swapchain in the correct
orientation when using the D3D11 renderer.
The trick is to add an extra uniform to each shader which takes either
the value +1.0 or -1.0. When rendering to a texture, ANGLE sets this
value to -1.0. When rendering to the default framebuffer, ANGLE sets
this value to +1.0. ANGLE multiplies vertex positions by this value in
the VS to invert rendering when appropriate. It also corrects other
state (e.g. viewport/scissor rect) and shader built-in values
(e.g. gl_FragCoord).
This saves a substantial amount of GPU time and lowers power
consumption. For example, the old method (where ANGLE renders all
content onto an offscreen texture, and then copies/inverts this onto the
swapchain at eglSwapBuffers() time) uses about 20% of the GPU each frame
on a Lumia 630.
Verification:
+ dEQP GL ES2 tests pass when "present path fast" is enabled
+ all ANGLE_end2end_tests pass when "present path fast" is enabled
BUG=angleproject:1219
Change-Id: I56b339897828753a616d7bae837a2f354dba9c63
Reviewed-on: https://chromium-review.googlesource.com/326730
Tryjob-Request: Austin Kinross <aukinros@microsoft.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/compiler/translator/OutputHLSL.cpp b/src/compiler/translator/OutputHLSL.cpp
index 170875e..253b966 100644
--- a/src/compiler/translator/OutputHLSL.cpp
+++ b/src/compiler/translator/OutputHLSL.cpp
@@ -505,6 +505,13 @@
out << " float3 dx_DepthFront : packoffset(c2);\n";
}
+ if (mUsesFragCoord)
+ {
+ // dx_ViewScale is only used in the fragment shader to correct
+ // the value for glFragCoord if necessary
+ out << " float2 dx_ViewScale : packoffset(c3);\n";
+ }
+
out << "};\n";
}
else
@@ -599,11 +606,13 @@
out << " float3 dx_DepthRange : packoffset(c0);\n";
}
- // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9 shaders.
- // However, we declare it for all shaders (including Feature Level 10+).
- // The bytecode is the same whether we declare it or not, since D3DCompiler removes it if it's unused.
+ // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9
+ // shaders. However, we declare it for all shaders (including Feature Level 10+).
+ // The bytecode is the same whether we declare it or not, since D3DCompiler removes it
+ // if it's unused.
out << " float4 dx_ViewAdjust : packoffset(c1);\n";
out << " float2 dx_ViewCoords : packoffset(c2);\n";
+ out << " float2 dx_ViewScale : packoffset(c3);\n";
out << "};\n"
"\n";
diff --git a/src/libANGLE/Caps.cpp b/src/libANGLE/Caps.cpp
index 1c5edcc..1eb54a1 100644
--- a/src/libANGLE/Caps.cpp
+++ b/src/libANGLE/Caps.cpp
@@ -697,6 +697,7 @@
deviceCreation(false),
deviceCreationD3D11(false),
x11Visual(false),
+ experimentalPresentPath(false),
clientGetAllProcAddresses(false)
{
}
@@ -716,6 +717,7 @@
InsertExtensionString("EGL_ANGLE_device_creation", deviceCreation, &extensionStrings);
InsertExtensionString("EGL_ANGLE_device_creation_d3d11", deviceCreationD3D11, &extensionStrings);
InsertExtensionString("EGL_ANGLE_x11_visual", x11Visual, &extensionStrings);
+ InsertExtensionString("EGL_ANGLE_experimental_present_path", experimentalPresentPath, &extensionStrings);
InsertExtensionString("EGL_KHR_client_get_all_proc_addresses", clientGetAllProcAddresses, &extensionStrings);
// clang-format on
diff --git a/src/libANGLE/Caps.h b/src/libANGLE/Caps.h
index 5d94851..d0e839a 100644
--- a/src/libANGLE/Caps.h
+++ b/src/libANGLE/Caps.h
@@ -529,6 +529,9 @@
// EGL_ANGLE_x11_visual
bool x11Visual;
+ // EGL_ANGLE_experimental_present_path
+ bool experimentalPresentPath;
+
// EGL_KHR_client_get_all_proc_addresses
bool clientGetAllProcAddresses;
};
diff --git a/src/libANGLE/Display.cpp b/src/libANGLE/Display.cpp
index 378b795..486c74a 100644
--- a/src/libANGLE/Display.cpp
+++ b/src/libANGLE/Display.cpp
@@ -882,6 +882,7 @@
#if defined(ANGLE_ENABLE_D3D11)
extensions.deviceCreation = true;
extensions.deviceCreationD3D11 = true;
+ extensions.experimentalPresentPath = true;
#endif
#if defined(ANGLE_USE_X11)
diff --git a/src/libANGLE/renderer/d3d/DynamicHLSL.cpp b/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
index 1d07b95..42a534f 100644
--- a/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
+++ b/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
@@ -412,6 +412,9 @@
const ShaderD3D *fragmentShader = GetImplAs<ShaderD3D>(fragmentShaderGL);
const int shaderModel = mRenderer->getMajorShaderModel();
+ // usesViewScale() isn't supported in the D3D9 renderer
+ ASSERT(shaderModel >= 4 || !programMetadata.usesViewScale());
+
bool useInstancedPointSpriteEmulation =
programMetadata.usesPointSize() &&
mRenderer->getWorkarounds().useInstancedPointSpriteEmulation;
@@ -464,18 +467,43 @@
// On D3D9 or D3D11 Feature Level 9, we need to emulate large viewports using dx_ViewAdjust.
if (shaderModel >= 4 && mRenderer->getShaderModelSuffix() == "")
{
- vertexStream << " output.dx_Position.x = gl_Position.x;\n"
- << " output.dx_Position.y = -gl_Position.y;\n"
- << " output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
+ vertexStream << " output.dx_Position.x = gl_Position.x;\n";
+
+ if (programMetadata.usesViewScale())
+ {
+ // This code assumes that dx_ViewScale.y = -1.0f when rendering to texture, and +1.0f
+ // when rendering to the default framebuffer. No other values are valid.
+ vertexStream << " output.dx_Position.y = dx_ViewScale.y * gl_Position.y;\n";
+ }
+ else
+ {
+ vertexStream << " output.dx_Position.y = - gl_Position.y;\n";
+ }
+
+ vertexStream << " output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
<< " output.dx_Position.w = gl_Position.w;\n";
}
else
{
vertexStream << " output.dx_Position.x = gl_Position.x * dx_ViewAdjust.z + "
- "dx_ViewAdjust.x * gl_Position.w;\n"
- << " output.dx_Position.y = -(gl_Position.y * dx_ViewAdjust.w + "
- "dx_ViewAdjust.y * gl_Position.w);\n"
- << " output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
+ "dx_ViewAdjust.x * gl_Position.w;\n";
+
+ // If usesViewScale() is true and we're using the D3D11 renderer via Feature Level 9_*,
+ // then we need to multiply the gl_Position.y by the viewScale.
+ // usesViewScale() isn't supported when using the D3D9 renderer.
+ if (programMetadata.usesViewScale() &&
+ (shaderModel >= 4 && mRenderer->getShaderModelSuffix() != ""))
+ {
+ vertexStream << " output.dx_Position.y = dx_ViewScale.y * (gl_Position.y * "
+ "dx_ViewAdjust.w + dx_ViewAdjust.y * gl_Position.w);\n";
+ }
+ else
+ {
+ vertexStream << " output.dx_Position.y = -(gl_Position.y * dx_ViewAdjust.w + "
+ "dx_ViewAdjust.y * gl_Position.w);\n";
+ }
+
+ vertexStream << " output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
<< " output.dx_Position.w = gl_Position.w;\n";
}
@@ -523,11 +551,26 @@
if (useInstancedPointSpriteEmulation)
{
vertexStream << "\n"
- << " gl_PointSize = clamp(gl_PointSize, minPointSize, maxPointSize);\n"
- << " output.dx_Position.xyz += float3(input.spriteVertexPos.x * "
- "gl_PointSize / (dx_ViewCoords.x*2), input.spriteVertexPos.y * "
- "gl_PointSize / (dx_ViewCoords.y*2), input.spriteVertexPos.z) * "
- "output.dx_Position.w;\n";
+ << " gl_PointSize = clamp(gl_PointSize, minPointSize, maxPointSize);\n";
+
+ vertexStream << " output.dx_Position.x += (input.spriteVertexPos.x * gl_PointSize / "
+ "(dx_ViewCoords.x*2)) * output.dx_Position.w;";
+
+ if (programMetadata.usesViewScale())
+ {
+ // Multiply by ViewScale to invert the rendering when appropriate
+ vertexStream << " output.dx_Position.y += (-dx_ViewScale.y * "
+ "input.spriteVertexPos.y * gl_PointSize / (dx_ViewCoords.y*2)) * "
+ "output.dx_Position.w;";
+ }
+ else
+ {
+ vertexStream << " output.dx_Position.y += (input.spriteVertexPos.y * gl_PointSize / "
+ "(dx_ViewCoords.y*2)) * output.dx_Position.w;";
+ }
+
+ vertexStream
+ << " output.dx_Position.z += input.spriteVertexPos.z * output.dx_Position.w;\n";
if (programMetadata.usesPointCoord())
{
@@ -606,6 +649,49 @@
"dx_ViewCoords.w;\n";
}
+ if (programMetadata.usesViewScale())
+ {
+ // For Feature Level 9_3 and below, we need to correct gl_FragCoord.y to account
+ // for dx_ViewScale. On Feature Level 10_0+, gl_FragCoord.y is calculated above using
+ // dx_ViewCoords and is always correct irrespective of dx_ViewScale's value.
+ // NOTE: usesViewScale() can only be true on D3D11 (i.e. Shader Model 4.0+).
+ if (shaderModel >= 4 && mRenderer->getShaderModelSuffix() == "")
+ {
+ // Some assumptions:
+ // - dx_ViewScale.y = -1.0f when rendering to texture
+ // - dx_ViewScale.y = +1.0f when rendering to the default framebuffer
+ // - gl_FragCoord.y has been set correctly above.
+ //
+ // When rendering to the backbuffer, the code inverts gl_FragCoord's y coordinate.
+ // This involves subtracting the y coordinate from the height of the area being
+ // rendered to.
+ //
+ // First we calculate the height of the area being rendered to:
+ // render_area_height = (2.0f / (1.0f - input.gl_FragCoord.y * rhw)) *
+ // gl_FragCoord.y
+ //
+ // Note that when we're rendering to default FB, we want our output to be
+ // equivalent to:
+ // "gl_FragCoord.y = render_area_height - gl_FragCoord.y"
+ //
+ // When we're rendering to a texture, we want our output to be equivalent to:
+ // "gl_FragCoord.y = gl_FragCoord.y;"
+ //
+ // If we set scale_factor = ((1.0f + dx_ViewScale.y) / 2.0f), then notice that
+ // - When rendering to default FB: scale_factor = 1.0f
+ // - When rendering to texture: scale_factor = 0.0f
+ //
+ // Therefore, we can get our desired output by setting:
+ // "gl_FragCoord.y = scale_factor * render_area_height - dx_ViewScale.y *
+ // gl_FragCoord.y"
+ //
+ // Simplifying, this becomes:
+ pixelStream
+ << " gl_FragCoord.y = (1.0f + dx_ViewScale.y) * gl_FragCoord.y /"
+ "(1.0f - input.gl_FragCoord.y * rhw) - dx_ViewScale.y * gl_FragCoord.y;\n";
+ }
+ }
+
pixelStream << " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + "
"dx_DepthFront.y;\n"
<< " gl_FragCoord.w = rhw;\n";
@@ -749,6 +835,7 @@
std::string DynamicHLSL::generateGeometryShaderHLSL(gl::PrimitiveType primitiveType,
const gl::Data &data,
const gl::Program::Data &programData,
+ const bool useViewScale,
const std::string &preambleString) const
{
ASSERT(mRenderer->getMajorShaderModel() >= 4);
@@ -799,8 +886,14 @@
{
shaderStream << "#define ANGLE_POINT_SPRITE_SHADER\n"
"\n"
- "uniform float4 dx_ViewCoords : register(c1);\n"
- "\n"
+ "uniform float4 dx_ViewCoords : register(c1);\n";
+
+ if (useViewScale)
+ {
+ shaderStream << "uniform float2 dx_ViewScale : register(c3);\n";
+ }
+
+ shaderStream << "\n"
"static float2 pointSpriteCorners[] = \n"
"{\n"
" float2( 0.5f, -0.5f),\n"
@@ -870,9 +963,20 @@
for (int corner = 0; corner < 4; corner++)
{
- shaderStream << "\n"
- " output.dx_Position = dx_Position + float4(pointSpriteCorners["
- << corner << "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
+ if (useViewScale)
+ {
+ shaderStream << " \n"
+ " output.dx_Position = dx_Position + float4(1.0f, "
+ "-dx_ViewScale.y, 1.0f, 1.0f)"
+ " * float4(pointSpriteCorners["
+ << corner << "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
+ }
+ else
+ {
+ shaderStream << "\n"
+ " output.dx_Position = dx_Position + float4(pointSpriteCorners["
+ << corner << "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
+ }
if (usesPointCoord)
{
diff --git a/src/libANGLE/renderer/d3d/DynamicHLSL.h b/src/libANGLE/renderer/d3d/DynamicHLSL.h
index df52d24..69d941c 100644
--- a/src/libANGLE/renderer/d3d/DynamicHLSL.h
+++ b/src/libANGLE/renderer/d3d/DynamicHLSL.h
@@ -74,6 +74,7 @@
std::string generateGeometryShaderHLSL(gl::PrimitiveType primitiveType,
const gl::Data &data,
const gl::Program::Data &programData,
+ const bool useViewScale,
const std::string &preambleString) const;
void getPixelShaderOutputKey(const gl::Data &data,
diff --git a/src/libANGLE/renderer/d3d/ProgramD3D.cpp b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
index bde3409..37a288e 100644
--- a/src/libANGLE/renderer/d3d/ProgramD3D.cpp
+++ b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
@@ -401,11 +401,13 @@
ProgramD3DMetadata::ProgramD3DMetadata(int rendererMajorShaderModel,
const std::string &shaderModelSuffix,
bool usesInstancedPointSpriteEmulation,
+ bool usesViewScale,
const ShaderD3D *vertexShader,
const ShaderD3D *fragmentShader)
: mRendererMajorShaderModel(rendererMajorShaderModel),
mShaderModelSuffix(shaderModelSuffix),
mUsesInstancedPointSpriteEmulation(usesInstancedPointSpriteEmulation),
+ mUsesViewScale(usesViewScale),
mVertexShader(vertexShader),
mFragmentShader(fragmentShader)
{
@@ -446,6 +448,11 @@
return !usesPointSize() && usesPointCoord() && mRendererMajorShaderModel >= 4;
}
+bool ProgramD3DMetadata::usesViewScale() const
+{
+ return mUsesViewScale;
+}
+
bool ProgramD3DMetadata::addsPointCoordToVertexShader() const
{
// Instanced PointSprite emulation requires that gl_PointCoord is present in the vertex shader
@@ -1259,7 +1266,8 @@
}
std::string geometryHLSL = mDynamicHLSL->generateGeometryShaderHLSL(
- geometryShaderType, data, mData, mGeometryShaderPreamble);
+ geometryShaderType, data, mData, mRenderer->presentPathFastEnabled(),
+ mGeometryShaderPreamble);
gl::InfoLog tempInfoLog;
gl::InfoLog *currentInfoLog = infoLog ? infoLog : &tempInfoLog;
@@ -1387,7 +1395,8 @@
}
ProgramD3DMetadata metadata(mRenderer->getMajorShaderModel(), mRenderer->getShaderModelSuffix(),
- usesInstancedPointSpriteEmulation(), vertexShaderD3D,
+ usesInstancedPointSpriteEmulation(),
+ mRenderer->presentPathFastEnabled(), vertexShaderD3D,
fragmentShaderD3D);
varyingPacking.enableBuiltins(SHADER_VERTEX, metadata);
diff --git a/src/libANGLE/renderer/d3d/ProgramD3D.h b/src/libANGLE/renderer/d3d/ProgramD3D.h
index 240cea1..3dfe52d 100644
--- a/src/libANGLE/renderer/d3d/ProgramD3D.h
+++ b/src/libANGLE/renderer/d3d/ProgramD3D.h
@@ -103,6 +103,7 @@
ProgramD3DMetadata(int rendererMajorShaderModel,
const std::string &shaderModelSuffix,
bool usesInstancedPointSpriteEmulation,
+ bool usesViewScale,
const ShaderD3D *vertexShader,
const ShaderD3D *fragmentShader);
@@ -113,6 +114,7 @@
bool usesFragCoord() const;
bool usesPointSize() const;
bool usesInsertedPointCoordValue() const;
+ bool usesViewScale() const;
bool addsPointCoordToVertexShader() const;
bool usesTransformFeedbackGLPosition() const;
bool usesSystemValuePointSize() const;
@@ -124,6 +126,7 @@
const int mRendererMajorShaderModel;
const std::string mShaderModelSuffix;
const bool mUsesInstancedPointSpriteEmulation;
+ const bool mUsesViewScale;
const ShaderD3D *mVertexShader;
const ShaderD3D *mFragmentShader;
};
diff --git a/src/libANGLE/renderer/d3d/RendererD3D.cpp b/src/libANGLE/renderer/d3d/RendererD3D.cpp
index 11a6860..7dfb118 100644
--- a/src/libANGLE/renderer/d3d/RendererD3D.cpp
+++ b/src/libANGLE/renderer/d3d/RendererD3D.cpp
@@ -41,6 +41,7 @@
: mDisplay(display),
mDeviceLost(false),
mAnnotator(nullptr),
+ mPresentPathFastEnabled(false),
mScratchMemoryBufferResetCounter(0),
mWorkaroundsInitialized(false),
mDisjoint(false)
diff --git a/src/libANGLE/renderer/d3d/RendererD3D.h b/src/libANGLE/renderer/d3d/RendererD3D.h
index b9d050e..32ccf28 100644
--- a/src/libANGLE/renderer/d3d/RendererD3D.h
+++ b/src/libANGLE/renderer/d3d/RendererD3D.h
@@ -251,6 +251,8 @@
virtual egl::Error getEGLDevice(DeviceImpl **device) = 0;
+ bool presentPathFastEnabled() const { return mPresentPathFastEnabled; }
+
protected:
virtual bool getLUID(LUID *adapterLuid) const = 0;
virtual gl::Error applyShadersImpl(const gl::Data &data, GLenum drawMode) = 0;
@@ -270,6 +272,8 @@
std::vector<TranslatedAttribute> mTranslatedAttribCache;
+ bool mPresentPathFastEnabled;
+
private:
gl::Error genericDrawArrays(const gl::Data &data,
GLenum mode,
@@ -329,20 +333,6 @@
bool mDisjoint;
};
-struct dx_VertexConstants
-{
- float depthRange[4];
- float viewAdjust[4];
- float viewCoords[4];
-};
-
-struct dx_PixelConstants
-{
- float depthRange[4];
- float viewCoords[4];
- float depthFront[4];
-};
-
}
#endif // LIBANGLE_RENDERER_D3D_RENDERERD3D_H_
diff --git a/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp b/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp
index ad2360d..beffa30 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp
@@ -93,7 +93,27 @@
gl::Error Framebuffer11::clear(const gl::Data &data, const ClearParameters &clearParams)
{
Clear11 *clearer = mRenderer->getClearer();
- gl::Error error = clearer->clearFramebuffer(clearParams, mData);
+ gl::Error error(GL_NO_ERROR);
+
+ const gl::FramebufferAttachment *colorAttachment = mData.getFirstColorAttachment();
+ if (clearParams.scissorEnabled == true && colorAttachment != nullptr &&
+ UsePresentPathFast(mRenderer, colorAttachment))
+ {
+ // If the current framebuffer is using the default colorbuffer, and present path fast is
+ // active, and the scissor rect is enabled, then we should invert the scissor rect
+ // vertically
+ ClearParameters presentPathFastClearParams = clearParams;
+ gl::Extents framebufferSize = colorAttachment->getSize();
+ presentPathFastClearParams.scissor.y = framebufferSize.height -
+ presentPathFastClearParams.scissor.y -
+ presentPathFastClearParams.scissor.height;
+ error = clearer->clearFramebuffer(presentPathFastClearParams, mData);
+ }
+ else
+ {
+ error = clearer->clearFramebuffer(clearParams, mData);
+ }
+
if (error.isError())
{
return error;
@@ -328,8 +348,27 @@
}
ASSERT(drawRenderTarget);
- error = mRenderer->blitRenderbufferRect(sourceArea, destArea, readRenderTarget, drawRenderTarget,
- filter, scissor, blitRenderTarget, false, false);
+ const bool invertColorSource = UsePresentPathFast(mRenderer, readBuffer);
+ gl::Rectangle actualSourceArea = sourceArea;
+ if (invertColorSource)
+ {
+ RenderTarget11 *readRenderTarget11 = GetAs<RenderTarget11>(readRenderTarget);
+ actualSourceArea.y = readRenderTarget11->getHeight() - sourceArea.y;
+ actualSourceArea.height = -sourceArea.height;
+ }
+
+ const bool invertColorDest = UsePresentPathFast(mRenderer, &drawBuffer);
+ gl::Rectangle actualDestArea = destArea;
+ if (invertColorDest)
+ {
+ RenderTarget11 *drawRenderTarget11 = GetAs<RenderTarget11>(drawRenderTarget);
+ actualDestArea.y = drawRenderTarget11->getHeight() - destArea.y;
+ actualDestArea.height = -destArea.height;
+ }
+
+ error = mRenderer->blitRenderbufferRect(actualSourceArea, actualDestArea,
+ readRenderTarget, drawRenderTarget, filter,
+ scissor, blitRenderTarget, false, false);
if (error.isError())
{
return error;
diff --git a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
index 537af0e..d0f22e4 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
@@ -473,6 +473,10 @@
default:
UNREACHABLE();
}
+
+ const EGLenum presentPath = attributes.get(EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE,
+ EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE);
+ mPresentPathFastEnabled = (presentPath == EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE);
}
else if (display->getPlatform() == EGL_PLATFORM_DEVICE_EXT)
{
@@ -483,6 +487,7 @@
// Also set EGL_PLATFORM_ANGLE_ANGLE variables, in case they're used elsewhere in ANGLE
// mAvailableFeatureLevels defaults to empty
mRequestedDriverType = D3D_DRIVER_TYPE_UNKNOWN;
+ mPresentPathFastEnabled = false;
}
initializeDebugAnnotator();
@@ -871,14 +876,24 @@
egl::ConfigSet Renderer11::generateConfigs() const
{
- static const GLenum colorBufferFormats[] = {
- // 32-bit supported formats
- GL_BGRA8_EXT, GL_RGBA8_OES,
- // 24-bit supported formats
- GL_RGB8_OES,
+ std::vector<GLenum> colorBufferFormats;
+
+ // 32-bit supported formats
+ colorBufferFormats.push_back(GL_BGRA8_EXT);
+ colorBufferFormats.push_back(GL_RGBA8_OES);
+
+ // 24-bit supported formats
+ colorBufferFormats.push_back(GL_RGB8_OES);
+
+ if (!mPresentPathFastEnabled)
+ {
// 16-bit supported formats
- GL_RGBA4, GL_RGB5_A1, GL_RGB565,
- };
+ // These aren't valid D3D11 swapchain formats, so don't expose them as configs
+ // if present path fast is active
+ colorBufferFormats.push_back(GL_RGBA4);
+ colorBufferFormats.push_back(GL_RGB5_A1);
+ colorBufferFormats.push_back(GL_RGB565);
+ }
static const GLenum depthStencilBufferFormats[] =
{
@@ -890,67 +905,87 @@
const gl::Caps &rendererCaps = getRendererCaps();
const gl::TextureCapsMap &rendererTextureCaps = getRendererTextureCaps();
- const EGLint optimalSurfaceOrientation = EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE;
+ const EGLint optimalSurfaceOrientation =
+ mPresentPathFastEnabled ? 0 : EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE;
egl::ConfigSet configs;
- for (size_t formatIndex = 0; formatIndex < ArraySize(colorBufferFormats); formatIndex++)
+ for (GLenum colorBufferInternalFormat : colorBufferFormats)
{
- GLenum colorBufferInternalFormat = colorBufferFormats[formatIndex];
const gl::TextureCaps &colorBufferFormatCaps = rendererTextureCaps.get(colorBufferInternalFormat);
- if (colorBufferFormatCaps.renderable)
+ if (!colorBufferFormatCaps.renderable)
{
- for (size_t depthStencilIndex = 0; depthStencilIndex < ArraySize(depthStencilBufferFormats); depthStencilIndex++)
+ continue;
+ }
+
+ for (GLenum depthStencilBufferInternalFormat : depthStencilBufferFormats)
+ {
+ const gl::TextureCaps &depthStencilBufferFormatCaps =
+ rendererTextureCaps.get(depthStencilBufferInternalFormat);
+ if (!depthStencilBufferFormatCaps.renderable &&
+ depthStencilBufferInternalFormat != GL_NONE)
{
- GLenum depthStencilBufferInternalFormat = depthStencilBufferFormats[depthStencilIndex];
- const gl::TextureCaps &depthStencilBufferFormatCaps = rendererTextureCaps.get(depthStencilBufferInternalFormat);
- if (depthStencilBufferFormatCaps.renderable || depthStencilBufferInternalFormat == GL_NONE)
- {
- const gl::InternalFormat &colorBufferFormatInfo = gl::GetInternalFormatInfo(colorBufferInternalFormat);
- const gl::InternalFormat &depthStencilBufferFormatInfo = gl::GetInternalFormatInfo(depthStencilBufferInternalFormat);
-
- egl::Config config;
- config.renderTargetFormat = colorBufferInternalFormat;
- config.depthStencilFormat = depthStencilBufferInternalFormat;
- config.bufferSize = colorBufferFormatInfo.pixelBytes * 8;
- config.redSize = colorBufferFormatInfo.redBits;
- config.greenSize = colorBufferFormatInfo.greenBits;
- config.blueSize = colorBufferFormatInfo.blueBits;
- config.luminanceSize = colorBufferFormatInfo.luminanceBits;
- config.alphaSize = colorBufferFormatInfo.alphaBits;
- config.alphaMaskSize = 0;
- config.bindToTextureRGB = (colorBufferFormatInfo.format == GL_RGB);
- config.bindToTextureRGBA = (colorBufferFormatInfo.format == GL_RGBA || colorBufferFormatInfo.format == GL_BGRA_EXT);
- config.colorBufferType = EGL_RGB_BUFFER;
- config.configCaveat = EGL_NONE;
- config.configID = static_cast<EGLint>(configs.size() + 1);
- // Can only support a conformant ES2 with feature level greater than 10.0.
- config.conformant = (mRenderer11DeviceCaps.featureLevel >= D3D_FEATURE_LEVEL_10_0) ? (EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT_KHR) : 0;
- config.depthSize = depthStencilBufferFormatInfo.depthBits;
- config.level = 0;
- config.matchNativePixmap = EGL_NONE;
- config.maxPBufferWidth = rendererCaps.max2DTextureSize;
- config.maxPBufferHeight = rendererCaps.max2DTextureSize;
- config.maxPBufferPixels = rendererCaps.max2DTextureSize * rendererCaps.max2DTextureSize;
- config.maxSwapInterval = 4;
- config.minSwapInterval = 0;
- config.nativeRenderable = EGL_FALSE;
- config.nativeVisualID = 0;
- config.nativeVisualType = EGL_NONE;
- // Can't support ES3 at all without feature level 10.0
- config.renderableType = EGL_OPENGL_ES2_BIT | ((mRenderer11DeviceCaps.featureLevel >= D3D_FEATURE_LEVEL_10_0) ? EGL_OPENGL_ES3_BIT_KHR : 0);
- config.sampleBuffers = 0; // FIXME: enumerate multi-sampling
- config.samples = 0;
- config.stencilSize = depthStencilBufferFormatInfo.stencilBits;
- config.surfaceType = EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
- config.transparentType = EGL_NONE;
- config.transparentRedValue = 0;
- config.transparentGreenValue = 0;
- config.transparentBlueValue = 0;
- config.optimalOrientation = optimalSurfaceOrientation;
-
- configs.add(config);
- }
+ continue;
}
+
+ const gl::InternalFormat &colorBufferFormatInfo =
+ gl::GetInternalFormatInfo(colorBufferInternalFormat);
+ const gl::InternalFormat &depthStencilBufferFormatInfo =
+ gl::GetInternalFormatInfo(depthStencilBufferInternalFormat);
+
+ egl::Config config;
+ config.renderTargetFormat = colorBufferInternalFormat;
+ config.depthStencilFormat = depthStencilBufferInternalFormat;
+ config.bufferSize = colorBufferFormatInfo.pixelBytes * 8;
+ config.redSize = colorBufferFormatInfo.redBits;
+ config.greenSize = colorBufferFormatInfo.greenBits;
+ config.blueSize = colorBufferFormatInfo.blueBits;
+ config.luminanceSize = colorBufferFormatInfo.luminanceBits;
+ config.alphaSize = colorBufferFormatInfo.alphaBits;
+ config.alphaMaskSize = 0;
+ config.bindToTextureRGB = (colorBufferFormatInfo.format == GL_RGB);
+ config.bindToTextureRGBA = (colorBufferFormatInfo.format == GL_RGBA ||
+ colorBufferFormatInfo.format == GL_BGRA_EXT);
+ config.colorBufferType = EGL_RGB_BUFFER;
+ config.configCaveat = EGL_NONE;
+ config.configID = static_cast<EGLint>(configs.size() + 1);
+ // Can only support a conformant ES2 with feature level greater than 10.0.
+ config.conformant = (mRenderer11DeviceCaps.featureLevel >= D3D_FEATURE_LEVEL_10_0)
+ ? (EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT_KHR)
+ : 0;
+
+ // PresentPathFast may not be conformant
+ if (mPresentPathFastEnabled)
+ {
+ config.conformant = 0;
+ }
+
+ config.depthSize = depthStencilBufferFormatInfo.depthBits;
+ config.level = 0;
+ config.matchNativePixmap = EGL_NONE;
+ config.maxPBufferWidth = rendererCaps.max2DTextureSize;
+ config.maxPBufferHeight = rendererCaps.max2DTextureSize;
+ config.maxPBufferPixels = rendererCaps.max2DTextureSize * rendererCaps.max2DTextureSize;
+ config.maxSwapInterval = 4;
+ config.minSwapInterval = 0;
+ config.nativeRenderable = EGL_FALSE;
+ config.nativeVisualID = 0;
+ config.nativeVisualType = EGL_NONE;
+ // Can't support ES3 at all without feature level 10.0
+ config.renderableType =
+ EGL_OPENGL_ES2_BIT | ((mRenderer11DeviceCaps.featureLevel >= D3D_FEATURE_LEVEL_10_0)
+ ? EGL_OPENGL_ES3_BIT_KHR
+ : 0);
+ config.sampleBuffers = 0; // FIXME: enumerate multi-sampling
+ config.samples = 0;
+ config.stencilSize = depthStencilBufferFormatInfo.stencilBits;
+ config.surfaceType = EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
+ config.transparentType = EGL_NONE;
+ config.transparentRedValue = 0;
+ config.transparentGreenValue = 0;
+ config.transparentBlueValue = 0;
+ config.optimalOrientation = optimalSurfaceOrientation;
+
+ configs.add(config);
}
}
@@ -971,7 +1006,9 @@
outExtensions->keyedMutex = true;
outExtensions->querySurfacePointer = true;
outExtensions->windowFixedSize = true;
- outExtensions->surfaceOrientation = true;
+
+ // If present path fast is active then the surface orientation extension isn't supported
+ outExtensions->surfaceOrientation = !mPresentPathFastEnabled;
// D3D11 does not support present with dirty rectangles until DXGI 1.2.
outExtensions->postSubBuffer = mRenderer11DeviceCaps.supportsDXGI1_2;
@@ -1352,6 +1389,12 @@
return error;
}
+ // Set the present path state
+ const bool presentPathFastActive =
+ UsePresentPathFast(this, framebufferObject->getFirstColorbuffer());
+ mStateManager.updatePresentPath(presentPathFastActive,
+ framebufferObject->getFirstColorbuffer());
+
// Setting viewport state
mStateManager.setViewport(data.caps, data.state->getViewport(), data.state->getNearPlane(),
data.state->getFarPlane());
@@ -2097,7 +2140,7 @@
if (!mDriverConstantBufferVS)
{
D3D11_BUFFER_DESC constantBufferDescription = {0};
- constantBufferDescription.ByteWidth = sizeof(dx_VertexConstants);
+ constantBufferDescription.ByteWidth = sizeof(dx_VertexConstants11);
constantBufferDescription.Usage = D3D11_USAGE_DEFAULT;
constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
constantBufferDescription.CPUAccessFlags = 0;
@@ -2116,7 +2159,7 @@
if (!mDriverConstantBufferPS)
{
D3D11_BUFFER_DESC constantBufferDescription = {0};
- constantBufferDescription.ByteWidth = sizeof(dx_PixelConstants);
+ constantBufferDescription.ByteWidth = sizeof(dx_PixelConstants11);
constantBufferDescription.Usage = D3D11_USAGE_DEFAULT;
constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
constantBufferDescription.CPUAccessFlags = 0;
@@ -2132,27 +2175,27 @@
mDeviceContext->PSSetConstantBuffers(1, 1, &mDriverConstantBufferPS);
}
- const dx_VertexConstants &vertexConstants = mStateManager.getVertexConstants();
- if (memcmp(&vertexConstants, &mAppliedVertexConstants, sizeof(dx_VertexConstants)) != 0)
+ const dx_VertexConstants11 &vertexConstants = mStateManager.getVertexConstants();
+ if (memcmp(&vertexConstants, &mAppliedVertexConstants, sizeof(dx_VertexConstants11)) != 0)
{
ASSERT(mDriverConstantBufferVS != nullptr);
if (mDriverConstantBufferVS)
{
mDeviceContext->UpdateSubresource(mDriverConstantBufferVS, 0, NULL, &vertexConstants,
16, 0);
- memcpy(&mAppliedVertexConstants, &vertexConstants, sizeof(dx_VertexConstants));
+ memcpy(&mAppliedVertexConstants, &vertexConstants, sizeof(dx_VertexConstants11));
}
}
- const dx_PixelConstants &pixelConstants = mStateManager.getPixelConstants();
- if (memcmp(&pixelConstants, &mAppliedPixelConstants, sizeof(dx_PixelConstants)) != 0)
+ const dx_PixelConstants11 &pixelConstants = mStateManager.getPixelConstants();
+ if (memcmp(&pixelConstants, &mAppliedPixelConstants, sizeof(dx_PixelConstants11)) != 0)
{
ASSERT(mDriverConstantBufferPS != nullptr);
if (mDriverConstantBufferPS)
{
mDeviceContext->UpdateSubresource(mDriverConstantBufferPS, 0, NULL, &pixelConstants, 16,
0);
- memcpy(&mAppliedPixelConstants, &pixelConstants, sizeof(dx_PixelConstants));
+ memcpy(&mAppliedPixelConstants, &pixelConstants, sizeof(dx_PixelConstants11));
}
}
@@ -2206,8 +2249,8 @@
mAppliedTFOffsets[i] = 0;
}
- memset(&mAppliedVertexConstants, 0, sizeof(dx_VertexConstants));
- memset(&mAppliedPixelConstants, 0, sizeof(dx_PixelConstants));
+ memset(&mAppliedVertexConstants, 0, sizeof(dx_VertexConstants11));
+ memset(&mAppliedPixelConstants, 0, sizeof(dx_PixelConstants11));
mInputLayoutCache.markDirty();
@@ -2602,6 +2645,13 @@
gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1);
gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1);
+ const bool invertSource = UsePresentPathFast(this, colorbuffer);
+ if (invertSource)
+ {
+ sourceArea.y = sourceSize.height - sourceRect.y;
+ sourceArea.height = -sourceArea.height;
+ }
+
gl::Box destArea(destOffset.x, destOffset.y, 0, sourceRect.width, sourceRect.height, 1);
gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1);
@@ -2654,6 +2704,13 @@
gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1);
gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1);
+ const bool invertSource = UsePresentPathFast(this, colorbuffer);
+ if (invertSource)
+ {
+ sourceArea.y = sourceSize.height - sourceRect.y;
+ sourceArea.height = -sourceArea.height;
+ }
+
gl::Box destArea(destOffset.x, destOffset.y, 0, sourceRect.width, sourceRect.height, 1);
gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1);
@@ -3333,6 +3390,8 @@
ASSERT(sourceArea.width >= 0);
ASSERT(sourceArea.height >= 0);
+ const bool invertTexture = UsePresentPathFast(this, &srcAttachment);
+
RenderTargetD3D *renderTarget = nullptr;
gl::Error error = srcAttachment.getRenderTarget(&renderTarget);
if (error.isError())
@@ -3348,15 +3407,21 @@
const gl::Extents &texSize = textureHelper.getExtents();
+ gl::Rectangle actualArea = sourceArea;
+ if (invertTexture)
+ {
+ actualArea.y = texSize.height - actualArea.y - actualArea.height;
+ }
+
// Clamp read region to the defined texture boundaries, preventing out of bounds reads
// and reads of uninitialized data.
gl::Rectangle safeArea;
- safeArea.x = gl::clamp(sourceArea.x, 0, texSize.width);
- safeArea.y = gl::clamp(sourceArea.y, 0, texSize.height);
+ safeArea.x = gl::clamp(actualArea.x, 0, texSize.width);
+ safeArea.y = gl::clamp(actualArea.y, 0, texSize.height);
safeArea.width =
- gl::clamp(sourceArea.width + std::min(sourceArea.x, 0), 0, texSize.width - safeArea.x);
+ gl::clamp(actualArea.width + std::min(actualArea.x, 0), 0, texSize.width - safeArea.x);
safeArea.height =
- gl::clamp(sourceArea.height + std::min(sourceArea.y, 0), 0, texSize.height - safeArea.y);
+ gl::clamp(actualArea.height + std::min(actualArea.y, 0), 0, texSize.height - safeArea.y);
ASSERT(safeArea.x >= 0 && safeArea.y >= 0);
ASSERT(safeArea.x + safeArea.width <= texSize.width);
@@ -3433,8 +3498,30 @@
mDeviceContext->CopySubresourceRegion(stagingHelper.getResource(), 0, 0, 0, 0,
srcTexture->getResource(), sourceSubResource, &srcBox);
- PackPixelsParams packParams(safeArea, format, type, outputPitch, pack, 0);
- return packPixels(stagingHelper, packParams, pixelsOut);
+ if (invertTexture)
+ {
+ gl::PixelPackState invertTexturePack;
+
+ // Create a new PixelPackState with reversed row order. Note that we can't just assign
+ // 'invertTexturePack' to be 'pack' (or memcpy) since that breaks the ref counting/object
+ // tracking in the 'pixelBuffer' members, causing leaks. Instead we must use
+ // pixelBuffer.set() twice, which performs the addRef/release correctly
+ invertTexturePack.alignment = pack.alignment;
+ invertTexturePack.pixelBuffer.set(pack.pixelBuffer.get());
+ invertTexturePack.reverseRowOrder = !pack.reverseRowOrder;
+
+ PackPixelsParams packParams(safeArea, format, type, outputPitch, invertTexturePack, 0);
+ error = packPixels(stagingHelper, packParams, pixelsOut);
+
+ invertTexturePack.pixelBuffer.set(nullptr);
+
+ return error;
+ }
+ else
+ {
+ PackPixelsParams packParams(safeArea, format, type, outputPitch, pack, 0);
+ return packPixels(stagingHelper, packParams, pixelsOut);
+ }
}
gl::Error Renderer11::packPixels(const TextureHelper11 &textureHelper,
diff --git a/src/libANGLE/renderer/d3d/d3d11/Renderer11.h b/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
index 8a53c80..ced90d3 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
+++ b/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
@@ -389,14 +389,14 @@
uintptr_t mAppliedGeometryShader;
uintptr_t mAppliedPixelShader;
- dx_VertexConstants mAppliedVertexConstants;
+ dx_VertexConstants11 mAppliedVertexConstants;
ID3D11Buffer *mDriverConstantBufferVS;
ID3D11Buffer *mCurrentVertexConstantBuffer;
unsigned int mCurrentConstantBufferVS[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS];
GLintptr mCurrentConstantBufferVSOffset[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS];
GLsizeiptr mCurrentConstantBufferVSSize[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS];
- dx_PixelConstants mAppliedPixelConstants;
+ dx_PixelConstants11 mAppliedPixelConstants;
ID3D11Buffer *mDriverConstantBufferPS;
ID3D11Buffer *mCurrentPixelConstantBuffer;
unsigned int mCurrentConstantBufferPS[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS];
diff --git a/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp b/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
index 68af21b..aa34fd4 100644
--- a/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
@@ -215,6 +215,23 @@
}
}
+void StateManager11::updatePresentPath(bool presentPathFastActive,
+ const gl::FramebufferAttachment *framebufferAttachment)
+{
+ const int colorBufferHeight =
+ framebufferAttachment ? framebufferAttachment->getSize().height : 0;
+
+ if ((mCurPresentPathFastEnabled != presentPathFastActive) ||
+ (presentPathFastActive && (colorBufferHeight != mCurPresentPathFastColorBufferHeight)))
+ {
+ mCurPresentPathFastEnabled = presentPathFastActive;
+ mCurPresentPathFastColorBufferHeight = colorBufferHeight;
+ mViewportStateIsDirty = true; // Viewport may need to be vertically inverted
+ mScissorStateIsDirty = true; // Scissor rect may need to be vertically inverted
+ mRasterizerStateIsDirty = true; // Cull Mode may need to be inverted
+ }
+}
+
void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits)
{
if (!dirtyBits.any())
@@ -571,8 +588,34 @@
}
ID3D11RasterizerState *dxRasterState = nullptr;
- gl::Error error = mRenderer->getStateCache().getRasterizerState(rasterState, mCurScissorEnabled,
- &dxRasterState);
+ gl::Error error(GL_NO_ERROR);
+
+ if (mCurPresentPathFastEnabled)
+ {
+ gl::RasterizerState modifiedRasterState = rasterState;
+
+ // If prseent path fast is active then we need invert the front face state.
+ // This ensures that both gl_FrontFacing is correct, and front/back culling
+ // is performed correctly.
+ if (modifiedRasterState.frontFace == GL_CCW)
+ {
+ modifiedRasterState.frontFace = GL_CW;
+ }
+ else
+ {
+ ASSERT(modifiedRasterState.frontFace == GL_CW);
+ modifiedRasterState.frontFace = GL_CCW;
+ }
+
+ error = mRenderer->getStateCache().getRasterizerState(modifiedRasterState,
+ mCurScissorEnabled, &dxRasterState);
+ }
+ else
+ {
+ error = mRenderer->getStateCache().getRasterizerState(rasterState, mCurScissorEnabled,
+ &dxRasterState);
+ }
+
if (error.isError())
{
return error;
@@ -591,13 +634,19 @@
if (!mScissorStateIsDirty)
return;
+ int modifiedScissorY = scissor.y;
+ if (mCurPresentPathFastEnabled)
+ {
+ modifiedScissorY = mCurPresentPathFastColorBufferHeight - scissor.height - scissor.y;
+ }
+
if (enabled)
{
D3D11_RECT rect;
rect.left = std::max(0, scissor.x);
- rect.top = std::max(0, scissor.y);
+ rect.top = std::max(0, modifiedScissorY);
rect.right = scissor.x + std::max(0, scissor.width);
- rect.bottom = scissor.y + std::max(0, scissor.height);
+ rect.bottom = modifiedScissorY + std::max(0, scissor.height);
mRenderer->getDeviceContext()->RSSetScissorRects(1, &rect);
}
@@ -639,7 +688,22 @@
D3D11_VIEWPORT dxViewport;
dxViewport.TopLeftX = static_cast<float>(dxViewportTopLeftX);
- dxViewport.TopLeftY = static_cast<float>(dxViewportTopLeftY);
+
+ if (mCurPresentPathFastEnabled)
+ {
+ // When present path fast is active and we're rendering to framebuffer 0, we must invert
+ // the viewport in Y-axis.
+ // NOTE: We delay the inversion until right before the call to RSSetViewports, and leave
+ // dxViewportTopLeftY unchanged. This allows us to calculate viewAdjust below using the
+ // unaltered dxViewportTopLeftY value.
+ dxViewport.TopLeftY = static_cast<float>(mCurPresentPathFastColorBufferHeight -
+ dxViewportTopLeftY - dxViewportHeight);
+ }
+ else
+ {
+ dxViewport.TopLeftY = static_cast<float>(dxViewportTopLeftY);
+ }
+
dxViewport.Width = static_cast<float>(dxViewportWidth);
dxViewport.Height = static_cast<float>(dxViewportHeight);
dxViewport.MinDepth = actualZNear;
@@ -688,6 +752,16 @@
mPixelConstants.depthRange[1] = actualZFar;
mPixelConstants.depthRange[2] = actualZFar - actualZNear;
+ mPixelConstants.viewScale[0] = 1.0f;
+ mPixelConstants.viewScale[1] = mCurPresentPathFastEnabled ? 1.0f : -1.0f;
+ mPixelConstants.viewScale[2] = 1.0f;
+ mPixelConstants.viewScale[3] = 1.0f;
+
+ mVertexConstants.viewScale[0] = mPixelConstants.viewScale[0];
+ mVertexConstants.viewScale[1] = mPixelConstants.viewScale[1];
+ mVertexConstants.viewScale[2] = mPixelConstants.viewScale[2];
+ mVertexConstants.viewScale[3] = mPixelConstants.viewScale[3];
+
mViewportStateIsDirty = false;
}
diff --git a/src/libANGLE/renderer/d3d/d3d11/StateManager11.h b/src/libANGLE/renderer/d3d/d3d11/StateManager11.h
index e8f1e2b..f900882 100644
--- a/src/libANGLE/renderer/d3d/d3d11/StateManager11.h
+++ b/src/libANGLE/renderer/d3d/d3d11/StateManager11.h
@@ -24,6 +24,22 @@
struct RenderTargetDesc;
struct Renderer11DeviceCaps;
+struct dx_VertexConstants11
+{
+ float depthRange[4];
+ float viewAdjust[4];
+ float viewCoords[4];
+ float viewScale[4];
+};
+
+struct dx_PixelConstants11
+{
+ float depthRange[4];
+ float viewCoords[4];
+ float depthFront[4];
+ float viewScale[4];
+};
+
class StateManager11 final : angle::NonCopyable
{
public:
@@ -46,8 +62,11 @@
void setViewport(const gl::Caps *caps, const gl::Rectangle &viewport, float zNear, float zFar);
- const dx_VertexConstants &getVertexConstants() const { return mVertexConstants; }
- const dx_PixelConstants &getPixelConstants() const { return mPixelConstants; }
+ void updatePresentPath(bool presentPathFastActive,
+ const gl::FramebufferAttachment *framebufferAttachment);
+
+ const dx_VertexConstants11 &getVertexConstants() const { return mVertexConstants; }
+ const dx_PixelConstants11 &getPixelConstants() const { return mPixelConstants; }
void updateStencilSizeIfChanged(bool depthStencilInitialized, unsigned int stencilSize);
@@ -90,7 +109,7 @@
Optional<bool> mCurDisableDepth;
Optional<bool> mCurDisableStencil;
- // Currenly applied rasterizer state
+ // Currently applied rasterizer state
bool mRasterizerStateIsDirty;
gl::RasterizerState mCurRasterState;
@@ -106,8 +125,8 @@
float mCurFar;
// Things needed in viewport state
- dx_VertexConstants mVertexConstants;
- dx_PixelConstants mPixelConstants;
+ dx_VertexConstants11 mVertexConstants;
+ dx_PixelConstants11 mPixelConstants;
// Render target variables
gl::Extents mViewportBounds;
diff --git a/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp b/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp
index ec68019..a56d3fa 100644
--- a/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp
@@ -31,6 +31,17 @@
namespace rx
{
+namespace
+{
+bool NeedsOffscreenTexture(Renderer11 *renderer, NativeWindow nativeWindow, EGLint orientation)
+{
+ // We don't need an offscreen texture if either orientation = INVERT_Y,
+ // or present path fast is enabled and we're not rendering onto an offscreen surface.
+ return orientation != EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE &&
+ !(renderer->presentPathFastEnabled() && nativeWindow.getNativeWindow());
+}
+} // anonymous namespace
+
SwapChain11::SwapChain11(Renderer11 *renderer,
NativeWindow nativeWindow,
HANDLE shareHandle,
@@ -52,7 +63,7 @@
mBackBufferTexture(nullptr),
mBackBufferRTView(nullptr),
mBackBufferSRView(nullptr),
- mNeedsOffscreenTexture(orientation != EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE),
+ mNeedsOffscreenTexture(NeedsOffscreenTexture(renderer, nativeWindow, orientation)),
mOffscreenTexture(nullptr),
mOffscreenRTView(nullptr),
mOffscreenSRView(nullptr),
@@ -68,6 +79,8 @@
mColorRenderTarget(this, renderer, false),
mDepthStencilRenderTarget(this, renderer, true)
{
+ // Sanity check that if present path fast is active then we're using the default orientation
+ ASSERT(!mRenderer->presentPathFastEnabled() || orientation == 0);
}
SwapChain11::~SwapChain11()
diff --git a/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp b/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp
index b37ceaf..c0ce409 100644
--- a/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp
@@ -292,7 +292,7 @@
case D3D_FEATURE_LEVEL_9_3:
case D3D_FEATURE_LEVEL_9_2:
case D3D_FEATURE_LEVEL_9_1:
- return 2; // dx_ViewAdjust and dx_ViewCoords
+ return 3; // dx_ViewAdjust, dx_ViewCoords and dx_ViewScale
default:
UNREACHABLE();
@@ -313,7 +313,7 @@
case D3D_FEATURE_LEVEL_9_3:
case D3D_FEATURE_LEVEL_9_2:
case D3D_FEATURE_LEVEL_9_1:
- return 2;
+ return 3;
default:
UNREACHABLE();
@@ -1668,4 +1668,16 @@
return TextureHelper11::MakeAndPossess3D(stagingTex);
}
+bool UsePresentPathFast(const Renderer11 *renderer,
+ const gl::FramebufferAttachment *framebufferAttachment)
+{
+ if (framebufferAttachment == nullptr)
+ {
+ return false;
+ }
+
+ return (framebufferAttachment->type() == GL_FRAMEBUFFER_DEFAULT &&
+ renderer->presentPathFastEnabled());
+}
+
} // namespace rx
diff --git a/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h b/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h
index d84fb8a..72389e4 100644
--- a/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h
+++ b/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h
@@ -25,6 +25,7 @@
namespace rx
{
+class Renderer11;
class RenderTarget11;
struct WorkaroundsD3D;
struct Renderer11DeviceCaps;
@@ -377,6 +378,8 @@
const gl::Extents &size,
ID3D11Device *device);
+bool UsePresentPathFast(const Renderer11 *renderer, const gl::FramebufferAttachment *colorbuffer);
+
} // namespace rx
#endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_
diff --git a/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp b/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp
index 1ba736e..71f0e42 100644
--- a/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp
@@ -154,7 +154,8 @@
swapChainDesc.Stereo = FALSE;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
- swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
+ swapChainDesc.BufferUsage =
+ DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
swapChainDesc.BufferCount = 2;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
diff --git a/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp b/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp
index 693b768..1ed3645 100644
--- a/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp
@@ -257,7 +257,8 @@
swapChainDesc.Stereo = FALSE;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
- swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
+ swapChainDesc.BufferUsage =
+ DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
swapChainDesc.BufferCount = 2;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
diff --git a/src/libANGLE/renderer/d3d/d3d9/StateManager9.cpp b/src/libANGLE/renderer/d3d/d3d9/StateManager9.cpp
index 440a776..c4c600a 100644
--- a/src/libANGLE/renderer/d3d/d3d9/StateManager9.cpp
+++ b/src/libANGLE/renderer/d3d/d3d9/StateManager9.cpp
@@ -489,8 +489,8 @@
mCurIgnoreViewport = ignoreViewport;
// Setting shader constants
- dx_VertexConstants vc = {};
- dx_PixelConstants pc = {};
+ dx_VertexConstants9 vc = {};
+ dx_PixelConstants9 pc = {};
vc.viewAdjust[0] =
static_cast<float>((actualViewport.width - static_cast<int>(dxViewport.Width)) +
@@ -520,13 +520,13 @@
pc.depthRange[1] = actualZFar;
pc.depthRange[2] = actualZFar - actualZNear;
- if (memcmp(&vc, &mVertexConstants, sizeof(dx_VertexConstants)) != 0)
+ if (memcmp(&vc, &mVertexConstants, sizeof(dx_VertexConstants9)) != 0)
{
mVertexConstants = vc;
mDxUniformsDirty = true;
}
- if (memcmp(&pc, &mPixelConstants, sizeof(dx_PixelConstants)) != 0)
+ if (memcmp(&pc, &mPixelConstants, sizeof(dx_PixelConstants9)) != 0)
{
mPixelConstants = pc;
mDxUniformsDirty = true;
@@ -542,9 +542,9 @@
IDirect3DDevice9 *device = mRenderer9->getDevice();
device->SetVertexShaderConstantF(0, reinterpret_cast<float *>(&mVertexConstants),
- sizeof(dx_VertexConstants) / sizeof(float[4]));
+ sizeof(dx_VertexConstants9) / sizeof(float[4]));
device->SetPixelShaderConstantF(0, reinterpret_cast<float *>(&mPixelConstants),
- sizeof(dx_PixelConstants) / sizeof(float[4]));
+ sizeof(dx_PixelConstants9) / sizeof(float[4]));
mDxUniformsDirty = false;
}
diff --git a/src/libANGLE/renderer/d3d/d3d9/StateManager9.h b/src/libANGLE/renderer/d3d/d3d9/StateManager9.h
index 6306855..d8c1eb9 100644
--- a/src/libANGLE/renderer/d3d/d3d9/StateManager9.h
+++ b/src/libANGLE/renderer/d3d/d3d9/StateManager9.h
@@ -19,6 +19,20 @@
class Renderer9;
+struct dx_VertexConstants9
+{
+ float depthRange[4];
+ float viewAdjust[4];
+ float viewCoords[4];
+};
+
+struct dx_PixelConstants9
+{
+ float depthRange[4];
+ float viewCoords[4];
+ float depthFront[4];
+};
+
class StateManager9 final : angle::NonCopyable
{
public:
@@ -175,8 +189,8 @@
float mCurDepthFront;
bool mCurIgnoreViewport;
- dx_VertexConstants mVertexConstants;
- dx_PixelConstants mPixelConstants;
+ dx_VertexConstants9 mVertexConstants;
+ dx_PixelConstants9 mPixelConstants;
bool mDxUniformsDirty;
// FIXME: Unsupported by D3D9
diff --git a/src/libGLESv2/entry_points_egl_ext.cpp b/src/libGLESv2/entry_points_egl_ext.cpp
index 6af8a55..7536b19 100644
--- a/src/libGLESv2/entry_points_egl_ext.cpp
+++ b/src/libGLESv2/entry_points_egl_ext.cpp
@@ -163,6 +163,7 @@
bool minorVersionSpecified = false;
bool enableAutoTrimSpecified = false;
bool deviceTypeSpecified = false;
+ bool presentPathSpecified = false;
if (attrib_list)
{
@@ -228,6 +229,29 @@
enableAutoTrimSpecified = true;
break;
+ case EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE:
+ if (!clientExtensions.experimentalPresentPath)
+ {
+ SetGlobalError(
+ Error(EGL_BAD_ATTRIBUTE,
+ "EGL_ANGLE_experimental_present_path extension not active"));
+ return EGL_NO_DISPLAY;
+ }
+
+ switch (curAttrib[1])
+ {
+ case EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE:
+ case EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE:
+ break;
+ default:
+ SetGlobalError(
+ Error(EGL_BAD_ATTRIBUTE,
+ "Invalid value for EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE"));
+ return EGL_NO_DISPLAY;
+ }
+ presentPathSpecified = true;
+ break;
+
case EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE:
switch (curAttrib[1])
{
@@ -282,6 +306,14 @@
return EGL_NO_DISPLAY;
}
+ if (presentPathSpecified && platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
+ {
+ SetGlobalError(Error(EGL_BAD_ATTRIBUTE,
+ "EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE requires a device type of "
+ "EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE."));
+ return EGL_NO_DISPLAY;
+ }
+
if (deviceTypeSpecified && platformType != EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE &&
platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
{
diff --git a/src/tests/angle_end2end_tests.gypi b/src/tests/angle_end2end_tests.gypi
index 42e2704..2d9d87a 100644
--- a/src/tests/angle_end2end_tests.gypi
+++ b/src/tests/angle_end2end_tests.gypi
@@ -83,6 +83,7 @@
'<(angle_path)/src/tests/gl_tests/D3D11FormatTablesTest.cpp',
'<(angle_path)/src/tests/gl_tests/D3D11InputLayoutCacheTest.cpp',
'<(angle_path)/src/tests/egl_tests/EGLDeviceTest.cpp',
+ '<(angle_path)/src/tests/egl_tests/EGLPresentPathD3D11Test.cpp',
# TODO(cwallez) for Linux, requires a portable implementation of threads
'<(angle_path)/src/tests/egl_tests/EGLThreadTest.cpp',
],
diff --git a/src/tests/egl_tests/EGLPresentPathD3D11Test.cpp b/src/tests/egl_tests/EGLPresentPathD3D11Test.cpp
new file mode 100644
index 0000000..0b897ab
--- /dev/null
+++ b/src/tests/egl_tests/EGLPresentPathD3D11Test.cpp
@@ -0,0 +1,378 @@
+//
+// Copyright 2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "test_utils/ANGLETest.h"
+
+#include <cstdint>
+#include "com_utils.h"
+#include "OSWindow.h"
+#include <d3d11.h>
+
+using namespace angle;
+
+class EGLPresentPathD3D11 : public testing::TestWithParam<PlatformParameters>
+{
+ protected:
+ EGLPresentPathD3D11()
+ : mDisplay(EGL_NO_DISPLAY),
+ mContext(EGL_NO_CONTEXT),
+ mSurface(EGL_NO_SURFACE),
+ mOffscreenSurfaceD3D11Texture(nullptr),
+ mConfig(0),
+ mOSWindow(nullptr),
+ mWindowWidth(0)
+ {
+ }
+
+ void SetUp() override
+ {
+ mOSWindow = CreateOSWindow();
+ mWindowWidth = 64;
+ mOSWindow->initialize("EGLPresentPathD3D11", mWindowWidth, mWindowWidth);
+ }
+
+ void initializeEGL(bool usePresentPathFast)
+ {
+ int clientVersion = GetParam().majorVersion;
+
+ const char *extensionString =
+ static_cast<const char *>(eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS));
+ ASSERT_NE(nullptr, strstr(extensionString, "EGL_ANGLE_experimental_present_path"));
+
+ PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT =
+ reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(
+ eglGetProcAddress("eglGetPlatformDisplayEXT"));
+ ASSERT_NE(nullptr, eglGetPlatformDisplayEXT);
+
+ // Set up EGL Display
+ EGLint displayAttribs[] = {
+ EGL_PLATFORM_ANGLE_TYPE_ANGLE, GetParam().getRenderer(),
+ EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, GetParam().eglParameters.majorVersion,
+ EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, GetParam().eglParameters.majorVersion,
+ EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE,
+ usePresentPathFast ? EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE
+ : EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE,
+ EGL_NONE};
+ mDisplay =
+ eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, displayAttribs);
+ ASSERT_TRUE(EGL_NO_DISPLAY != mDisplay);
+ ASSERT_EGL_TRUE(eglInitialize(mDisplay, NULL, NULL));
+
+ // Choose the EGL config
+ EGLint numConfigs;
+ EGLint configAttribs[] = {EGL_RED_SIZE,
+ 8,
+ EGL_GREEN_SIZE,
+ 8,
+ EGL_BLUE_SIZE,
+ 8,
+ EGL_ALPHA_SIZE,
+ 8,
+ EGL_RENDERABLE_TYPE,
+ clientVersion == 3 ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT,
+ EGL_SURFACE_TYPE,
+ EGL_PBUFFER_BIT,
+ EGL_NONE};
+ ASSERT_EGL_TRUE(eglChooseConfig(mDisplay, configAttribs, &mConfig, 1, &numConfigs));
+ ASSERT_EQ(1, numConfigs);
+
+ // Set up the EGL context
+ EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, clientVersion, EGL_NONE};
+ mContext = eglCreateContext(mDisplay, mConfig, NULL, contextAttribs);
+ ASSERT_TRUE(EGL_NO_CONTEXT != mContext);
+ }
+
+ void createWindowSurface()
+ {
+ mSurface = eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(), nullptr);
+ }
+
+ void createPbufferFromClientBufferSurface()
+ {
+ EGLAttrib device = 0;
+ EGLAttrib angleDevice = 0;
+
+ PFNEGLQUERYDISPLAYATTRIBEXTPROC queryDisplayAttribEXT;
+ PFNEGLQUERYDEVICEATTRIBEXTPROC queryDeviceAttribEXT;
+
+ const char *extensionString =
+ static_cast<const char *>(eglQueryString(mDisplay, EGL_EXTENSIONS));
+ EXPECT_TRUE(strstr(extensionString, "EGL_EXT_device_query"));
+
+ queryDisplayAttribEXT =
+ (PFNEGLQUERYDISPLAYATTRIBEXTPROC)eglGetProcAddress("eglQueryDisplayAttribEXT");
+ queryDeviceAttribEXT =
+ (PFNEGLQUERYDEVICEATTRIBEXTPROC)eglGetProcAddress("eglQueryDeviceAttribEXT");
+ ASSERT_NE(nullptr, queryDisplayAttribEXT);
+ ASSERT_NE(nullptr, queryDeviceAttribEXT);
+
+ ASSERT_EGL_TRUE(queryDisplayAttribEXT(mDisplay, EGL_DEVICE_EXT, &angleDevice));
+ ASSERT_EGL_TRUE(queryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(angleDevice),
+ EGL_D3D11_DEVICE_ANGLE, &device));
+ ID3D11Device *d3d11Device = reinterpret_cast<ID3D11Device *>(device);
+
+ D3D11_TEXTURE2D_DESC textureDesc = {0};
+ textureDesc.Width = mWindowWidth;
+ textureDesc.Height = mWindowWidth;
+ textureDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
+ textureDesc.MipLevels = 1;
+ textureDesc.ArraySize = 1;
+ textureDesc.SampleDesc.Count = 1;
+ textureDesc.SampleDesc.Quality = 0;
+ textureDesc.Usage = D3D11_USAGE_DEFAULT;
+ textureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
+ textureDesc.CPUAccessFlags = 0;
+ textureDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
+
+ ASSERT_TRUE(SUCCEEDED(
+ d3d11Device->CreateTexture2D(&textureDesc, nullptr, &mOffscreenSurfaceD3D11Texture)));
+
+ IDXGIResource *dxgiResource =
+ DynamicCastComObject<IDXGIResource>(mOffscreenSurfaceD3D11Texture);
+ ASSERT_NE(nullptr, dxgiResource);
+
+ HANDLE sharedHandle = 0;
+ ASSERT_TRUE(SUCCEEDED(dxgiResource->GetSharedHandle(&sharedHandle)));
+ SafeRelease(dxgiResource);
+
+ EGLint pBufferAttributes[] = {EGL_WIDTH, mWindowWidth, EGL_HEIGHT,
+ mWindowWidth, EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
+ EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, EGL_NONE};
+
+ mSurface = eglCreatePbufferFromClientBuffer(mDisplay, EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE,
+ sharedHandle, mConfig, pBufferAttributes);
+ ASSERT_TRUE(EGL_NO_SURFACE != mSurface);
+ }
+
+ void makeCurrent() { ASSERT_EGL_TRUE(eglMakeCurrent(mDisplay, mSurface, mSurface, mContext)); }
+
+ void TearDown() override
+ {
+ if (mDisplay != EGL_NO_DISPLAY)
+ {
+ eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+ if (mSurface != EGL_NO_SURFACE)
+ {
+ eglDestroySurface(mDisplay, mSurface);
+ mSurface = EGL_NO_SURFACE;
+ }
+
+ if (mContext != EGL_NO_CONTEXT)
+ {
+ eglDestroyContext(mDisplay, mContext);
+ mContext = EGL_NO_CONTEXT;
+ }
+
+ eglTerminate(mDisplay);
+ mDisplay = EGL_NO_DISPLAY;
+ }
+
+ mOSWindow->destroy();
+ SafeDelete(mOSWindow);
+
+ SafeRelease(mOffscreenSurfaceD3D11Texture);
+ }
+
+ void drawQuadUsingGL()
+ {
+ GLuint m2DProgram;
+ GLint mTexture2DUniformLocation;
+
+ const std::string vertexShaderSource =
+ SHADER_SOURCE(precision highp float; attribute vec4 position; varying vec2 texcoord;
+
+ void main()
+ {
+ gl_Position = vec4(position.xy, 0.0, 1.0);
+ texcoord = (position.xy * 0.5) + 0.5;
+ });
+
+ const std::string fragmentShaderSource2D =
+ SHADER_SOURCE(precision highp float; uniform sampler2D tex; varying vec2 texcoord;
+
+ void main()
+ {
+ gl_FragColor = texture2D(tex, texcoord);
+ });
+
+ m2DProgram = CompileProgram(vertexShaderSource, fragmentShaderSource2D);
+ mTexture2DUniformLocation = glGetUniformLocation(m2DProgram, "tex");
+
+ uint8_t textureInitData[16] = {
+ 255, 0, 0, 255, // Red
+ 0, 255, 0, 255, // Green
+ 0, 0, 255, 255, // Blue
+ 255, 255, 0, 255 // Red + Green
+ };
+
+ // Create a simple RGBA texture
+ GLuint tex = 0;
+ glGenTextures(1, &tex);
+ glBindTexture(GL_TEXTURE_2D, tex);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ textureInitData);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ ASSERT_GL_NO_ERROR();
+
+ // Draw a quad using the texture
+ glClear(GL_COLOR_BUFFER_BIT);
+ glUseProgram(m2DProgram);
+ glUniform1i(mTexture2DUniformLocation, 0);
+
+ GLint positionLocation = glGetAttribLocation(m2DProgram, "position");
+ glUseProgram(m2DProgram);
+ 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);
+ ASSERT_GL_NO_ERROR();
+
+ glDeleteProgram(m2DProgram);
+ }
+
+ void checkPixelsUsingGL()
+ {
+ // Note that the texture is in BGRA format
+ EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255); // Red
+ EXPECT_PIXEL_EQ(mWindowWidth - 1, 0, 0, 255, 0, 255); // Green
+ EXPECT_PIXEL_EQ(0, mWindowWidth - 1, 0, 0, 255, 255); // Blue
+ EXPECT_PIXEL_EQ(mWindowWidth - 1, mWindowWidth - 1, 255, 255, 0, 255); // Red + green
+ }
+
+ void checkPixelsUsingD3D(bool usingPresentPathFast)
+ {
+ ASSERT_NE(nullptr, mOffscreenSurfaceD3D11Texture);
+
+ D3D11_TEXTURE2D_DESC textureDesc = {0};
+ ID3D11Device *device;
+ ID3D11DeviceContext *context;
+ mOffscreenSurfaceD3D11Texture->GetDesc(&textureDesc);
+ mOffscreenSurfaceD3D11Texture->GetDevice(&device);
+ device->GetImmediateContext(&context);
+ ASSERT_NE(nullptr, device);
+ ASSERT_NE(nullptr, context);
+
+ textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
+ textureDesc.Usage = D3D11_USAGE_STAGING;
+ textureDesc.BindFlags = 0;
+ textureDesc.MiscFlags = 0;
+ ID3D11Texture2D *cpuTexture = nullptr;
+ ASSERT_TRUE(SUCCEEDED(device->CreateTexture2D(&textureDesc, nullptr, &cpuTexture)));
+
+ context->CopyResource(cpuTexture, mOffscreenSurfaceD3D11Texture);
+
+ D3D11_MAPPED_SUBRESOURCE mappedSubresource;
+ context->Map(cpuTexture, 0, D3D11_MAP_READ, 0, &mappedSubresource);
+ ASSERT_EQ(static_cast<UINT>(mWindowWidth * 4), mappedSubresource.RowPitch);
+ ASSERT_EQ(static_cast<UINT>(mWindowWidth * mWindowWidth * 4), mappedSubresource.DepthPitch);
+
+ angle::GLColor *byteData = reinterpret_cast<angle::GLColor *>(mappedSubresource.pData);
+
+ // Note that the texture is in BGRA format, although the GLColor struct is RGBA
+ GLColor expectedTopLeftPixel = GLColor(0, 0, 255, 255); // Red
+ GLColor expectedTopRightPixel = GLColor(0, 255, 0, 255); // Green
+ GLColor expectedBottomLeftPixel = GLColor(255, 0, 0, 255); // Blue
+ GLColor expectedBottomRightPixel = GLColor(0, 255, 255, 255); // Red + Green
+
+ if (usingPresentPathFast)
+ {
+ // Invert the expected values
+ GLColor tempTopLeft = expectedTopLeftPixel;
+ GLColor tempTopRight = expectedTopRightPixel;
+ expectedTopLeftPixel = expectedBottomLeftPixel;
+ expectedTopRightPixel = expectedBottomRightPixel;
+ expectedBottomLeftPixel = tempTopLeft;
+ expectedBottomRightPixel = tempTopRight;
+ }
+
+ EXPECT_EQ(expectedTopLeftPixel, byteData[0]);
+ EXPECT_EQ(expectedTopRightPixel, byteData[(mWindowWidth - 1)]);
+ EXPECT_EQ(expectedBottomLeftPixel, byteData[(mWindowWidth - 1) * mWindowWidth]);
+ EXPECT_EQ(expectedBottomRightPixel,
+ byteData[(mWindowWidth - 1) * mWindowWidth + (mWindowWidth - 1)]);
+
+ context->Unmap(cpuTexture, 0);
+ SafeRelease(cpuTexture);
+ SafeRelease(device);
+ SafeRelease(context);
+ }
+
+ EGLDisplay mDisplay;
+ EGLContext mContext;
+ EGLSurface mSurface;
+ ID3D11Texture2D *mOffscreenSurfaceD3D11Texture;
+ EGLConfig mConfig;
+ OSWindow *mOSWindow;
+ GLint mWindowWidth;
+};
+
+// Test that rendering basic content onto a window surface when present path fast
+// is enabled works as expected
+TEST_P(EGLPresentPathD3D11, WindowPresentPathFast)
+{
+ initializeEGL(true);
+ createWindowSurface();
+ makeCurrent();
+
+ drawQuadUsingGL();
+
+ checkPixelsUsingGL();
+}
+
+// Test that rendering basic content onto a client buffer surface when present path fast
+// works as expected, and is also oriented the correct way around
+TEST_P(EGLPresentPathD3D11, ClientBufferPresentPathFast)
+{
+ initializeEGL(true);
+ createPbufferFromClientBufferSurface();
+ makeCurrent();
+
+ drawQuadUsingGL();
+
+ checkPixelsUsingGL();
+ checkPixelsUsingD3D(true);
+}
+
+// Test that rendering basic content onto a window surface when present path fast
+// is disabled works as expected
+TEST_P(EGLPresentPathD3D11, WindowPresentPathCopy)
+{
+ initializeEGL(false);
+ createWindowSurface();
+ makeCurrent();
+
+ drawQuadUsingGL();
+
+ checkPixelsUsingGL();
+}
+
+// Test that rendering basic content onto a client buffer surface when present path
+// fast is disabled works as expected, and is also oriented the correct way around
+TEST_P(EGLPresentPathD3D11, ClientBufferPresentPathCopy)
+{
+ initializeEGL(false);
+ createPbufferFromClientBufferSurface();
+ makeCurrent();
+
+ drawQuadUsingGL();
+
+ checkPixelsUsingGL();
+ checkPixelsUsingD3D(false);
+}
+
+ANGLE_INSTANTIATE_TEST(EGLPresentPathD3D11, ES2_D3D11(), ES2_D3D11_FL9_3());
\ No newline at end of file
diff --git a/src/tests/gl_tests/BlitFramebufferANGLETest.cpp b/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
index ed74371..2184086 100644
--- a/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
+++ b/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
@@ -892,4 +892,7 @@
// default framebuffer is BGRA to enable the GL and GLES backends. (http://anglebug.com/1289)
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
-ANGLE_INSTANTIATE_TEST(BlitFramebufferANGLETest, ES2_D3D9(), ES2_D3D11());
+ANGLE_INSTANTIATE_TEST(BlitFramebufferANGLETest,
+ ES2_D3D9(),
+ ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE),
+ ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE));
diff --git a/src/tests/gl_tests/CopyTexImageTest.cpp b/src/tests/gl_tests/CopyTexImageTest.cpp
index 5f7c3b8..00f14ba 100644
--- a/src/tests/gl_tests/CopyTexImageTest.cpp
+++ b/src/tests/gl_tests/CopyTexImageTest.cpp
@@ -302,7 +302,8 @@
// tests should be run against.
ANGLE_INSTANTIATE_TEST(CopyTexImageTest,
ES2_D3D9(),
- ES2_D3D11(),
+ ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE),
+ ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE),
ES2_OPENGL(),
ES2_OPENGL(3, 3),
ES2_OPENGLES());
diff --git a/src/tests/gl_tests/MipmapTest.cpp b/src/tests/gl_tests/MipmapTest.cpp
index 0c6f31b..fa73641 100644
--- a/src/tests/gl_tests/MipmapTest.cpp
+++ b/src/tests/gl_tests/MipmapTest.cpp
@@ -928,7 +928,8 @@
// Note: we run these tests against 9_3 on WARP due to hardware driver issues on Win7
ANGLE_INSTANTIATE_TEST(MipmapTest,
ES2_D3D9(),
- ES2_D3D11(),
+ ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE),
+ ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE),
ES2_D3D11_FL9_3_WARP(),
ES2_OPENGL(),
ES3_OPENGL(),
diff --git a/src/tests/gl_tests/SimpleOperationTest.cpp b/src/tests/gl_tests/SimpleOperationTest.cpp
index 0790211..b11fb9f 100644
--- a/src/tests/gl_tests/SimpleOperationTest.cpp
+++ b/src/tests/gl_tests/SimpleOperationTest.cpp
@@ -201,7 +201,8 @@
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_INSTANTIATE_TEST(SimpleOperationTest,
ES2_D3D9(),
- ES2_D3D11(),
+ ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE),
+ ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE),
ES3_D3D11(),
ES2_OPENGL(),
ES3_OPENGL(),
diff --git a/src/tests/gl_tests/ViewportTest.cpp b/src/tests/gl_tests/ViewportTest.cpp
index 06ab874..8cd9cd3 100644
--- a/src/tests/gl_tests/ViewportTest.cpp
+++ b/src/tests/gl_tests/ViewportTest.cpp
@@ -263,7 +263,8 @@
// D3D11 Feature Level 9 and D3D9 emulate large and negative viewports in the vertex shader. We should test both of these as well as D3D11 Feature Level 10_0+.
ANGLE_INSTANTIATE_TEST(ViewportTest,
ES2_D3D9(),
- ES2_D3D11(),
+ ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE),
+ ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE),
ES2_D3D11_FL9_3(),
ES2_OPENGLES(),
ES3_OPENGLES());
diff --git a/src/tests/test_utils/angle_test_configs.cpp b/src/tests/test_utils/angle_test_configs.cpp
index fabb2e7..0ed7a74 100644
--- a/src/tests/test_utils/angle_test_configs.cpp
+++ b/src/tests/test_utils/angle_test_configs.cpp
@@ -113,6 +113,25 @@
break;
}
+ switch (pp.eglParameters.presentPath)
+ {
+ case EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE:
+ stream << "_PRESENT_PATH_COPY";
+ break;
+
+ case EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE:
+ stream << "_PRESENT_PATH_FAST";
+ break;
+
+ case EGL_DONT_CARE:
+ // default
+ break;
+
+ default:
+ UNREACHABLE();
+ break;
+ }
+
return stream;
}
@@ -165,6 +184,12 @@
EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE);
}
+EGLPlatformParameters D3D11(EGLenum presentPath)
+{
+ return EGLPlatformParameters(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_DONT_CARE, EGL_DONT_CARE,
+ EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE, presentPath);
+}
+
EGLPlatformParameters D3D11_FL11_1()
{
return EGLPlatformParameters(
@@ -360,6 +385,11 @@
return PlatformParameters(2, 0, egl_platform::D3D11());
}
+PlatformParameters ES2_D3D11(EGLenum presentPath)
+{
+ return PlatformParameters(2, 0, egl_platform::D3D11(presentPath));
+}
+
PlatformParameters ES2_D3D11_FL11_0()
{
return PlatformParameters(2, 0, egl_platform::D3D11_FL11_0());
diff --git a/src/tests/test_utils/angle_test_configs.h b/src/tests/test_utils/angle_test_configs.h
index ca2cee3..a40a7a1 100644
--- a/src/tests/test_utils/angle_test_configs.h
+++ b/src/tests/test_utils/angle_test_configs.h
@@ -52,6 +52,7 @@
EGLPlatformParameters D3D9_REFERENCE();
EGLPlatformParameters D3D11();
+EGLPlatformParameters D3D11(EGLenum presentPath);
EGLPlatformParameters D3D11_FL11_1();
EGLPlatformParameters D3D11_FL11_0();
EGLPlatformParameters D3D11_FL10_1();
@@ -88,6 +89,7 @@
PlatformParameters ES2_D3D9_REFERENCE();
PlatformParameters ES2_D3D11();
+PlatformParameters ES2_D3D11(EGLenum presentPath);
PlatformParameters ES2_D3D11_FL11_0();
PlatformParameters ES2_D3D11_FL10_1();
PlatformParameters ES2_D3D11_FL10_0();