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