1 //
2 // Copyright 2014 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // Framebuffer11.cpp: Implements the Framebuffer11 class.
8
9 #include "libANGLE/renderer/d3d/d3d11/Framebuffer11.h"
10
11 #include "common/bitset_utils.h"
12 #include "common/debug.h"
13 #include "libANGLE/Context.h"
14 #include "libANGLE/Framebuffer.h"
15 #include "libANGLE/FramebufferAttachment.h"
16 #include "libANGLE/Texture.h"
17 #include "libANGLE/renderer/d3d/TextureD3D.h"
18 #include "libANGLE/renderer/d3d/d3d11/Buffer11.h"
19 #include "libANGLE/renderer/d3d/d3d11/Clear11.h"
20 #include "libANGLE/renderer/d3d/d3d11/Context11.h"
21 #include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
22 #include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
23 #include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h"
24 #include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
25 #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
26
27 using namespace angle;
28
29 namespace rx
30 {
31
32 namespace
33 {
MarkAttachmentsDirty(const gl::Context * context,const gl::FramebufferAttachment * attachment)34 angle::Result MarkAttachmentsDirty(const gl::Context *context,
35 const gl::FramebufferAttachment *attachment)
36 {
37 if (attachment->type() == GL_TEXTURE)
38 {
39 gl::Texture *texture = attachment->getTexture();
40
41 TextureD3D *textureD3D = GetImplAs<TextureD3D>(texture);
42
43 TextureStorage *texStorage = nullptr;
44 ANGLE_TRY(textureD3D->getNativeTexture(context, &texStorage));
45
46 if (texStorage)
47 {
48 TextureStorage11 *texStorage11 = GetAs<TextureStorage11>(texStorage);
49 ASSERT(texStorage11);
50
51 texStorage11->markLevelDirty(attachment->mipLevel());
52 }
53 }
54
55 return angle::Result::Continue;
56 }
57 } // anonymous namespace
58
Framebuffer11(const gl::FramebufferState & data,Renderer11 * renderer)59 Framebuffer11::Framebuffer11(const gl::FramebufferState &data, Renderer11 *renderer)
60 : FramebufferD3D(data, renderer), mRenderer(renderer)
61 {
62 ASSERT(mRenderer != nullptr);
63 }
64
~Framebuffer11()65 Framebuffer11::~Framebuffer11() {}
66
markAttachmentsDirty(const gl::Context * context) const67 angle::Result Framebuffer11::markAttachmentsDirty(const gl::Context *context) const
68 {
69 const auto &colorAttachments = mState.getColorAttachments();
70 for (size_t drawBuffer : mState.getEnabledDrawBuffers())
71 {
72 const gl::FramebufferAttachment &colorAttachment = colorAttachments[drawBuffer];
73 ASSERT(colorAttachment.isAttached());
74 ANGLE_TRY(MarkAttachmentsDirty(context, &colorAttachment));
75 }
76
77 const gl::FramebufferAttachment *dsAttachment = mState.getDepthOrStencilAttachment();
78 if (dsAttachment)
79 {
80 ANGLE_TRY(MarkAttachmentsDirty(context, dsAttachment));
81 }
82
83 return angle::Result::Continue;
84 }
85
clearImpl(const gl::Context * context,const ClearParameters & clearParams)86 angle::Result Framebuffer11::clearImpl(const gl::Context *context,
87 const ClearParameters &clearParams)
88 {
89 Clear11 *clearer = mRenderer->getClearer();
90
91 const gl::FramebufferAttachment *colorAttachment = mState.getFirstColorAttachment();
92 if (clearParams.scissorEnabled == true && colorAttachment != nullptr &&
93 UsePresentPathFast(mRenderer, colorAttachment))
94 {
95 // If the current framebuffer is using the default colorbuffer, and present path fast is
96 // active, and the scissor rect is enabled, then we should invert the scissor rect
97 // vertically
98 ClearParameters presentPathFastClearParams = clearParams;
99 gl::Extents framebufferSize = colorAttachment->getSize();
100 presentPathFastClearParams.scissor.y = framebufferSize.height -
101 presentPathFastClearParams.scissor.y -
102 presentPathFastClearParams.scissor.height;
103 ANGLE_TRY(clearer->clearFramebuffer(context, presentPathFastClearParams, mState));
104 }
105 else
106 {
107 ANGLE_TRY(clearer->clearFramebuffer(context, clearParams, mState));
108 }
109
110 ANGLE_TRY(markAttachmentsDirty(context));
111
112 return angle::Result::Continue;
113 }
114
invalidate(const gl::Context * context,size_t count,const GLenum * attachments)115 angle::Result Framebuffer11::invalidate(const gl::Context *context,
116 size_t count,
117 const GLenum *attachments)
118 {
119 return invalidateBase(context, count, attachments, false);
120 }
121
discard(const gl::Context * context,size_t count,const GLenum * attachments)122 angle::Result Framebuffer11::discard(const gl::Context *context,
123 size_t count,
124 const GLenum *attachments)
125 {
126 return invalidateBase(context, count, attachments, true);
127 }
128
invalidateBase(const gl::Context * context,size_t count,const GLenum * attachments,bool useEXTBehavior) const129 angle::Result Framebuffer11::invalidateBase(const gl::Context *context,
130 size_t count,
131 const GLenum *attachments,
132 bool useEXTBehavior) const
133 {
134 ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported();
135
136 if (!deviceContext1)
137 {
138 // DiscardView() is only supported on ID3D11DeviceContext1
139 return angle::Result::Continue;
140 }
141
142 bool foundDepth = false;
143 bool foundStencil = false;
144
145 for (size_t i = 0; i < count; ++i)
146 {
147 switch (attachments[i])
148 {
149 // Handle depth and stencil attachments. Defer discarding until later.
150 case GL_DEPTH_STENCIL_ATTACHMENT:
151 foundDepth = true;
152 foundStencil = true;
153 break;
154 case GL_DEPTH_EXT:
155 case GL_DEPTH_ATTACHMENT:
156 foundDepth = true;
157 break;
158 case GL_STENCIL_EXT:
159 case GL_STENCIL_ATTACHMENT:
160 foundStencil = true;
161 break;
162 default:
163 {
164 // Handle color attachments
165 ASSERT((attachments[i] >= GL_COLOR_ATTACHMENT0 &&
166 attachments[i] <= GL_COLOR_ATTACHMENT15) ||
167 (attachments[i] == GL_COLOR));
168
169 size_t colorIndex =
170 (attachments[i] == GL_COLOR ? 0u : (attachments[i] - GL_COLOR_ATTACHMENT0));
171 const gl::FramebufferAttachment *colorAttachment =
172 mState.getColorAttachment(colorIndex);
173 if (colorAttachment)
174 {
175 ANGLE_TRY(invalidateAttachment(context, colorAttachment));
176 }
177 break;
178 }
179 }
180 }
181
182 bool discardDepth = false;
183 bool discardStencil = false;
184
185 // The D3D11 renderer uses the same view for depth and stencil buffers, so we must be careful.
186 if (useEXTBehavior)
187 {
188 // In the extension, if the app discards only one of the depth and stencil attachments, but
189 // those are backed by the same packed_depth_stencil buffer, then both images become
190 // undefined.
191 discardDepth = foundDepth;
192
193 // Don't bother discarding the stencil buffer if the depth buffer will already do it
194 discardStencil = foundStencil && (!discardDepth || mState.getDepthAttachment() == nullptr);
195 }
196 else
197 {
198 // In ES 3.0.4, if a specified attachment has base internal format DEPTH_STENCIL but the
199 // attachments list does not include DEPTH_STENCIL_ATTACHMENT or both DEPTH_ATTACHMENT and
200 // STENCIL_ATTACHMENT, then only the specified portion of every pixel in the subregion of
201 // pixels of the DEPTH_STENCIL buffer may be invalidated, and the other portion must be
202 // preserved.
203 discardDepth = (foundDepth && foundStencil) ||
204 (foundDepth && (mState.getStencilAttachment() == nullptr));
205 discardStencil = (foundStencil && (mState.getDepthAttachment() == nullptr));
206 }
207
208 if (discardDepth && mState.getDepthAttachment())
209 {
210 ANGLE_TRY(invalidateAttachment(context, mState.getDepthAttachment()));
211 }
212
213 if (discardStencil && mState.getStencilAttachment())
214 {
215 ANGLE_TRY(invalidateAttachment(context, mState.getStencilAttachment()));
216 }
217
218 return angle::Result::Continue;
219 }
220
invalidateSub(const gl::Context * context,size_t count,const GLenum * attachments,const gl::Rectangle & area)221 angle::Result Framebuffer11::invalidateSub(const gl::Context *context,
222 size_t count,
223 const GLenum *attachments,
224 const gl::Rectangle &area)
225 {
226 // A no-op implementation conforms to the spec, so don't call UNIMPLEMENTED()
227 return angle::Result::Continue;
228 }
229
invalidateAttachment(const gl::Context * context,const gl::FramebufferAttachment * attachment) const230 angle::Result Framebuffer11::invalidateAttachment(const gl::Context *context,
231 const gl::FramebufferAttachment *attachment) const
232 {
233 ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported();
234 ASSERT(deviceContext1);
235 ASSERT(attachment && attachment->isAttached());
236
237 RenderTarget11 *renderTarget = nullptr;
238 ANGLE_TRY(attachment->getRenderTarget(context, 0, &renderTarget));
239 const auto &rtv = renderTarget->getRenderTargetView();
240
241 if (rtv.valid())
242 {
243 deviceContext1->DiscardView(rtv.get());
244 }
245
246 return angle::Result::Continue;
247 }
248
readPixelsImpl(const gl::Context * context,const gl::Rectangle & area,GLenum format,GLenum type,size_t outputPitch,const gl::PixelPackState & pack,gl::Buffer * packBuffer,uint8_t * pixels)249 angle::Result Framebuffer11::readPixelsImpl(const gl::Context *context,
250 const gl::Rectangle &area,
251 GLenum format,
252 GLenum type,
253 size_t outputPitch,
254 const gl::PixelPackState &pack,
255 gl::Buffer *packBuffer,
256 uint8_t *pixels)
257 {
258 const gl::FramebufferAttachment *readAttachment = mState.getReadPixelsAttachment(format);
259 ASSERT(readAttachment);
260
261 if (packBuffer != nullptr)
262 {
263 Buffer11 *packBufferStorage = GetImplAs<Buffer11>(packBuffer);
264 const angle::Format &angleFormat = GetFormatFromFormatType(format, type);
265 PackPixelsParams packParams(area, angleFormat, static_cast<GLuint>(outputPitch),
266 pack.reverseRowOrder, packBuffer,
267 reinterpret_cast<ptrdiff_t>(pixels));
268
269 return packBufferStorage->packPixels(context, *readAttachment, packParams);
270 }
271
272 return mRenderer->readFromAttachment(context, *readAttachment, area, format, type,
273 static_cast<GLuint>(outputPitch), pack, pixels);
274 }
275
blitImpl(const gl::Context * context,const gl::Rectangle & sourceArea,const gl::Rectangle & destArea,const gl::Rectangle * scissor,bool blitRenderTarget,bool blitDepth,bool blitStencil,GLenum filter,const gl::Framebuffer * sourceFramebuffer)276 angle::Result Framebuffer11::blitImpl(const gl::Context *context,
277 const gl::Rectangle &sourceArea,
278 const gl::Rectangle &destArea,
279 const gl::Rectangle *scissor,
280 bool blitRenderTarget,
281 bool blitDepth,
282 bool blitStencil,
283 GLenum filter,
284 const gl::Framebuffer *sourceFramebuffer)
285 {
286 if (blitRenderTarget)
287 {
288 const gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getReadColorAttachment();
289 ASSERT(readBuffer);
290
291 RenderTargetD3D *readRenderTarget = nullptr;
292 ANGLE_TRY(readBuffer->getRenderTarget(context, 0, &readRenderTarget));
293 ASSERT(readRenderTarget);
294
295 const auto &colorAttachments = mState.getColorAttachments();
296 const auto &drawBufferStates = mState.getDrawBufferStates();
297
298 for (size_t colorAttachment = 0; colorAttachment < colorAttachments.size();
299 colorAttachment++)
300 {
301 const gl::FramebufferAttachment &drawBuffer = colorAttachments[colorAttachment];
302
303 if (drawBuffer.isAttached() && drawBufferStates[colorAttachment] != GL_NONE)
304 {
305 RenderTargetD3D *drawRenderTarget = nullptr;
306 ANGLE_TRY(drawBuffer.getRenderTarget(
307 context, drawBuffer.getRenderToTextureSamples(), &drawRenderTarget));
308 ASSERT(drawRenderTarget);
309
310 const bool invertColorSource = UsePresentPathFast(mRenderer, readBuffer);
311 gl::Rectangle actualSourceArea = sourceArea;
312 if (invertColorSource)
313 {
314 RenderTarget11 *readRenderTarget11 = GetAs<RenderTarget11>(readRenderTarget);
315 actualSourceArea.y = readRenderTarget11->getHeight() - sourceArea.y;
316 actualSourceArea.height = -sourceArea.height;
317 }
318
319 const bool invertColorDest = UsePresentPathFast(mRenderer, &drawBuffer);
320 gl::Rectangle actualDestArea = destArea;
321
322 const auto &surfaceTextureOffset = mState.getSurfaceTextureOffset();
323 actualDestArea.x = actualDestArea.x + surfaceTextureOffset.x;
324 actualDestArea.y = actualDestArea.y + surfaceTextureOffset.y;
325
326 if (invertColorDest)
327 {
328 RenderTarget11 *drawRenderTarget11 = GetAs<RenderTarget11>(drawRenderTarget);
329 actualDestArea.y = drawRenderTarget11->getHeight() - destArea.y;
330 actualDestArea.height = -destArea.height;
331 }
332
333 ANGLE_TRY(mRenderer->blitRenderbufferRect(
334 context, actualSourceArea, actualDestArea, readRenderTarget, drawRenderTarget,
335 filter, scissor, blitRenderTarget, false, false));
336 }
337 }
338 }
339
340 if (blitDepth || blitStencil)
341 {
342 const gl::FramebufferAttachment *readBuffer =
343 sourceFramebuffer->getDepthOrStencilAttachment();
344 ASSERT(readBuffer);
345 RenderTargetD3D *readRenderTarget = nullptr;
346 ANGLE_TRY(readBuffer->getRenderTarget(context, 0, &readRenderTarget));
347 ASSERT(readRenderTarget);
348
349 const bool invertSource = UsePresentPathFast(mRenderer, readBuffer);
350 gl::Rectangle actualSourceArea = sourceArea;
351 if (invertSource)
352 {
353 RenderTarget11 *readRenderTarget11 = GetAs<RenderTarget11>(readRenderTarget);
354 actualSourceArea.y = readRenderTarget11->getHeight() - sourceArea.y;
355 actualSourceArea.height = -sourceArea.height;
356 }
357
358 const gl::FramebufferAttachment *drawBuffer = mState.getDepthOrStencilAttachment();
359 ASSERT(drawBuffer);
360 RenderTargetD3D *drawRenderTarget = nullptr;
361 ANGLE_TRY(drawBuffer->getRenderTarget(context, drawBuffer->getRenderToTextureSamples(),
362 &drawRenderTarget));
363 ASSERT(drawRenderTarget);
364
365 bool invertDest = UsePresentPathFast(mRenderer, drawBuffer);
366 gl::Rectangle actualDestArea = destArea;
367 if (invertDest)
368 {
369 RenderTarget11 *drawRenderTarget11 = GetAs<RenderTarget11>(drawRenderTarget);
370 actualDestArea.y = drawRenderTarget11->getHeight() - destArea.y;
371 actualDestArea.height = -destArea.height;
372 }
373
374 ANGLE_TRY(mRenderer->blitRenderbufferRect(context, actualSourceArea, actualDestArea,
375 readRenderTarget, drawRenderTarget, filter,
376 scissor, false, blitDepth, blitStencil));
377 }
378
379 ANGLE_TRY(markAttachmentsDirty(context));
380 return angle::Result::Continue;
381 }
382
getImplementationColorReadFormat(const gl::Context * context) const383 const gl::InternalFormat &Framebuffer11::getImplementationColorReadFormat(
384 const gl::Context *context) const
385 {
386 Context11 *context11 = GetImplAs<Context11>(context);
387 const Renderer11DeviceCaps &caps = context11->getRenderer()->getRenderer11DeviceCaps();
388 GLenum sizedFormat = mState.getReadAttachment()->getFormat().info->sizedInternalFormat;
389 const angle::Format &angleFormat = d3d11::Format::Get(sizedFormat, caps).format();
390 return gl::GetSizedInternalFormatInfo(angleFormat.fboImplementationInternalFormat);
391 }
392
syncState(const gl::Context * context,GLenum binding,const gl::Framebuffer::DirtyBits & dirtyBits,gl::Command command)393 angle::Result Framebuffer11::syncState(const gl::Context *context,
394 GLenum binding,
395 const gl::Framebuffer::DirtyBits &dirtyBits,
396 gl::Command command)
397 {
398 ANGLE_TRY(mRenderTargetCache.update(context, mState, dirtyBits));
399 ANGLE_TRY(FramebufferD3D::syncState(context, binding, dirtyBits, command));
400
401 // Call this last to allow the state manager to take advantage of the cached render targets.
402 mRenderer->getStateManager()->invalidateRenderTarget();
403
404 // Call this to syncViewport for framebuffer default parameters.
405 if (mState.getDefaultWidth() != 0 || mState.getDefaultHeight() != 0)
406 {
407 mRenderer->getStateManager()->invalidateViewport(context);
408 }
409
410 return angle::Result::Continue;
411 }
412
getSamplePosition(const gl::Context * context,size_t index,GLfloat * xy) const413 angle::Result Framebuffer11::getSamplePosition(const gl::Context *context,
414 size_t index,
415 GLfloat *xy) const
416 {
417 const gl::FramebufferAttachment *attachment = mState.getFirstNonNullAttachment();
418 ASSERT(attachment);
419 GLsizei sampleCount = attachment->getSamples();
420
421 rx::GetSamplePosition(sampleCount, index, xy);
422 return angle::Result::Continue;
423 }
424
getFirstRenderTarget() const425 RenderTarget11 *Framebuffer11::getFirstRenderTarget() const
426 {
427 for (auto *renderTarget : mRenderTargetCache.getColors())
428 {
429 if (renderTarget)
430 {
431 return renderTarget;
432 }
433 }
434
435 return mRenderTargetCache.getDepthStencil();
436 }
437
438 } // namespace rx
439