-
Notifications
You must be signed in to change notification settings - Fork 15.1k
/
d3d11_skip_blits_if_there_is_no_intersection_of_dest_areas.patch
137 lines (123 loc) · 6.82 KB
/
d3d11_skip_blits_if_there_is_no_intersection_of_dest_areas.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Geoff Lang <geofflang@chromium.org>
Date: Mon, 19 Apr 2021 12:47:05 -0400
Subject: D3D11: Skip blits if there is no intersection of dest areas
Blit11 would clip the destination rectangle with the destination size
but ignore the result. gl::ClipRectangle returns false when the
rectangles do not intersect at all, indicating the blit can be skipped.
This could lead to an out-of-bounds write to the GPU memory for the
destination texture.
Mark ClipRectangle as nodiscard to prevent future issues.
Bug: chromium:1199402
Change-Id: I260e82d0917b8aa7e7887f2c9f7ed4b1a03ba785
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2836786
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Geoff Lang <geofflang@chromium.org>
(cherry picked from commit b574643ef28c92fcea5122dd7a72acb42a514eed)
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2846982
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/angletypes.h b/src/libANGLE/angletypes.h
index e9e955b58f053a4a895c3c3fa105aac9db3c8baf..37740dda4be1aa59b57529841e0f13ee8a349af6 100644
--- a/src/libANGLE/angletypes.h
+++ b/src/libANGLE/angletypes.h
@@ -62,7 +62,7 @@ struct Rectangle
bool operator==(const Rectangle &a, const Rectangle &b);
bool operator!=(const Rectangle &a, const Rectangle &b);
-bool ClipRectangle(const Rectangle &source, const Rectangle &clip, Rectangle *intersection);
+ANGLE_NO_DISCARD bool ClipRectangle(const Rectangle &source, const Rectangle &clip, Rectangle *intersection);
struct Offset
{
diff --git a/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp b/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp
index 55f8f8f4d38f30990d7061de6ebaa0595f0447da..6d9365af8db5fa9835127650162d5aeb6ce46b77 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp
@@ -141,7 +141,10 @@ void StretchedBlitNearest(const gl::Box &sourceArea,
uint8_t *destData)
{
gl::Rectangle clippedDestArea(destArea.x, destArea.y, destArea.width, destArea.height);
- gl::ClipRectangle(clippedDestArea, clipRect, &clippedDestArea);
+ if (!gl::ClipRectangle(clippedDestArea, clipRect, &clippedDestArea))
+ {
+ return;
+ }
// Determine if entire rows can be copied at once instead of each individual pixel. There
// must be no out of bounds lookups, whole rows copies, and no scale.
diff --git a/src/libANGLE/renderer/gl/FramebufferGL.cpp b/src/libANGLE/renderer/gl/FramebufferGL.cpp
index 2dd83c1f2d7c4be71bcc16a3c5d6f7f209a5b6b1..d709449547af9021ccf4ef2476e217af2f1517e5 100644
--- a/src/libANGLE/renderer/gl/FramebufferGL.cpp
+++ b/src/libANGLE/renderer/gl/FramebufferGL.cpp
@@ -1115,7 +1115,10 @@ angle::Result FramebufferGL::clipSrcRegion(const gl::Context *context,
// If pixels lying outside the read framebuffer, adjust src region
// and dst region to appropriate in-bounds regions respectively.
gl::Rectangle realSourceRegion;
- ClipRectangle(bounds.sourceRegion, bounds.sourceBounds, &realSourceRegion);
+ if (!ClipRectangle(bounds.sourceRegion, bounds.sourceBounds, &realSourceRegion))
+ {
+ return angle::Result::Stop;
+ }
GLuint xOffset = realSourceRegion.x - bounds.sourceRegion.x;
GLuint yOffset = realSourceRegion.y - bounds.sourceRegion.y;
diff --git a/src/libANGLE/renderer/metal/ContextMtl.mm b/src/libANGLE/renderer/metal/ContextMtl.mm
index d8d421f925675113a7d95250572e692fecb986ef..4bda9cf8518f24b8628ec4576e19ee7499131f10 100644
--- a/src/libANGLE/renderer/metal/ContextMtl.mm
+++ b/src/libANGLE/renderer/metal/ContextMtl.mm
@@ -1282,7 +1282,10 @@ void ContextMtl::updateScissor(const gl::State &glState)
// Clip the render area to the viewport.
gl::Rectangle viewportClippedRenderArea;
- gl::ClipRectangle(renderArea, glState.getViewport(), &viewportClippedRenderArea);
+ if (!gl::ClipRectangle(renderArea, glState.getViewport(), &viewportClippedRenderArea))
+ {
+ viewportClippedRenderArea = gl::Rectangle();
+ }
gl::Rectangle scissoredArea = ClipRectToScissor(getState(), viewportClippedRenderArea, false);
if (framebufferMtl->flipY())
diff --git a/src/libANGLE/renderer/vulkan/ContextVk.cpp b/src/libANGLE/renderer/vulkan/ContextVk.cpp
index 0276a4a8b579d36f239cd86527a6f8e08291d058..6092575364db4896caaf755eeaf93fb1d2fad9c4 100644
--- a/src/libANGLE/renderer/vulkan/ContextVk.cpp
+++ b/src/libANGLE/renderer/vulkan/ContextVk.cpp
@@ -2533,8 +2533,11 @@ angle::Result ContextVk::updateScissor(const gl::State &glState)
// Clip the render area to the viewport.
gl::Rectangle viewportClippedRenderArea;
- gl::ClipRectangle(renderArea, getCorrectedViewport(glState.getViewport()),
- &viewportClippedRenderArea);
+ if (!gl::ClipRectangle(renderArea, getCorrectedViewport(glState.getViewport()),
+ &viewportClippedRenderArea))
+ {
+ viewportClippedRenderArea = gl::Rectangle();
+ }
gl::Rectangle scissoredArea = ClipRectToScissor(getState(), viewportClippedRenderArea, false);
gl::Rectangle rotatedScissoredArea;
diff --git a/src/tests/gl_tests/BlitFramebufferANGLETest.cpp b/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
index 79ba46aa10ae8c689b1546b3e1e99ce815f414bd..b38bebb31f17d9f1d127e170495fd810aba21390 100644
--- a/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
+++ b/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
@@ -1997,6 +1997,30 @@ TEST_P(BlitFramebufferTest, BlitFramebufferSizeOverflow2)
EXPECT_GL_ERROR(GL_INVALID_VALUE);
}
+// Test an edge case in D3D11 stencil blitting on the CPU that does not properly clip the
+// destination regions
+TEST_P(BlitFramebufferTest, BlitFramebufferStencilClipNoIntersection)
+{
+ GLFramebuffer framebuffers[2];
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffers[0]);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffers[1]);
+
+ GLRenderbuffer renderbuffers[2];
+ glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[0]);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 4, 4);
+ glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
+ renderbuffers[0]);
+
+ glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[1]);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 4, 4);
+ glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
+ renderbuffers[1]);
+
+ glBlitFramebuffer(0, 0, 4, 4, 1 << 24, 1 << 24, 1 << 25, 1 << 25, GL_STENCIL_BUFFER_BIT,
+ GL_NEAREST);
+ EXPECT_GL_NO_ERROR();
+}
+
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
ANGLE_INSTANTIATE_TEST(BlitFramebufferANGLETest,