1 | // |
---|---|
2 | // Copyright 2016 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 | // FramebufferVk.cpp: |
7 | // Implements the class methods for FramebufferVk. |
8 | // |
9 | |
10 | #include "libANGLE/renderer/vulkan/FramebufferVk.h" |
11 | |
12 | #include <array> |
13 | |
14 | #include "common/debug.h" |
15 | #include "common/vulkan/vk_headers.h" |
16 | #include "libANGLE/Context.h" |
17 | #include "libANGLE/Display.h" |
18 | #include "libANGLE/ErrorStrings.h" |
19 | #include "libANGLE/formatutils.h" |
20 | #include "libANGLE/renderer/renderer_utils.h" |
21 | #include "libANGLE/renderer/vulkan/ContextVk.h" |
22 | #include "libANGLE/renderer/vulkan/DisplayVk.h" |
23 | #include "libANGLE/renderer/vulkan/RenderTargetVk.h" |
24 | #include "libANGLE/renderer/vulkan/RendererVk.h" |
25 | #include "libANGLE/renderer/vulkan/ResourceVk.h" |
26 | #include "libANGLE/renderer/vulkan/SurfaceVk.h" |
27 | #include "libANGLE/renderer/vulkan/vk_format_utils.h" |
28 | |
29 | namespace rx |
30 | { |
31 | |
32 | namespace |
33 | { |
34 | // Clear values are only used when loadOp=Clear is set in clearWithRenderPassOp. When starting a |
35 | // new render pass, the clear value is set to an unlikely value (bright pink) to stand out better |
36 | // in case of a bug. |
37 | constexpr VkClearValue kUninitializedClearValue = {.color: {.float32: {0.95, 0.05, 0.95, 0.95}}}; |
38 | |
39 | // The value to assign an alpha channel that's emulated. The type is unsigned int, though it will |
40 | // automatically convert to the actual data type. |
41 | constexpr unsigned int kEmulatedAlphaValue = 1; |
42 | |
43 | bool HasSrcBlitFeature(RendererVk *renderer, RenderTargetVk *srcRenderTarget) |
44 | { |
45 | angle::FormatID srcFormatID = srcRenderTarget->getImageActualFormatID(); |
46 | return renderer->hasImageFormatFeatureBits(format: srcFormatID, featureBits: VK_FORMAT_FEATURE_BLIT_SRC_BIT); |
47 | } |
48 | |
49 | bool HasDstBlitFeature(RendererVk *renderer, RenderTargetVk *dstRenderTarget) |
50 | { |
51 | angle::FormatID dstFormatID = dstRenderTarget->getImageActualFormatID(); |
52 | return renderer->hasImageFormatFeatureBits(format: dstFormatID, featureBits: VK_FORMAT_FEATURE_BLIT_DST_BIT); |
53 | } |
54 | |
55 | // Returns false if destination has any channel the source doesn't. This means that channel was |
56 | // emulated and using the Vulkan blit command would overwrite that emulated channel. |
57 | bool AreSrcAndDstColorChannelsBlitCompatible(RenderTargetVk *srcRenderTarget, |
58 | RenderTargetVk *dstRenderTarget) |
59 | { |
60 | const angle::Format &srcFormat = srcRenderTarget->getImageIntendedFormat(); |
61 | const angle::Format &dstFormat = dstRenderTarget->getImageIntendedFormat(); |
62 | |
63 | // Luminance/alpha formats are not renderable, so they can't have ended up in a framebuffer to |
64 | // participate in a blit. |
65 | ASSERT(!dstFormat.isLUMA() && !srcFormat.isLUMA()); |
66 | |
67 | // All color formats have the red channel. |
68 | ASSERT(dstFormat.redBits > 0 && srcFormat.redBits > 0); |
69 | |
70 | return (dstFormat.greenBits > 0 || srcFormat.greenBits == 0) && |
71 | (dstFormat.blueBits > 0 || srcFormat.blueBits == 0) && |
72 | (dstFormat.alphaBits > 0 || srcFormat.alphaBits == 0); |
73 | } |
74 | |
75 | // Returns false if formats are not identical. vkCmdResolveImage and resolve attachments both |
76 | // require identical formats between source and destination. vkCmdBlitImage additionally requires |
77 | // the same for depth/stencil formats. |
78 | bool AreSrcAndDstFormatsIdentical(RenderTargetVk *srcRenderTarget, RenderTargetVk *dstRenderTarget) |
79 | { |
80 | angle::FormatID srcFormatID = srcRenderTarget->getImageActualFormatID(); |
81 | angle::FormatID dstFormatID = dstRenderTarget->getImageActualFormatID(); |
82 | |
83 | return srcFormatID == dstFormatID; |
84 | } |
85 | |
86 | bool AreSrcAndDstDepthStencilChannelsBlitCompatible(RenderTargetVk *srcRenderTarget, |
87 | RenderTargetVk *dstRenderTarget) |
88 | { |
89 | const angle::Format &srcFormat = srcRenderTarget->getImageIntendedFormat(); |
90 | const angle::Format &dstFormat = dstRenderTarget->getImageIntendedFormat(); |
91 | |
92 | return (dstFormat.depthBits > 0 || srcFormat.depthBits == 0) && |
93 | (dstFormat.stencilBits > 0 || srcFormat.stencilBits == 0); |
94 | } |
95 | |
96 | void EarlyAdjustFlipYForPreRotation(SurfaceRotation blitAngleIn, |
97 | SurfaceRotation *blitAngleOut, |
98 | bool *blitFlipYOut) |
99 | { |
100 | switch (blitAngleIn) |
101 | { |
102 | case SurfaceRotation::Identity: |
103 | // No adjustments needed |
104 | break; |
105 | case SurfaceRotation::Rotated90Degrees: |
106 | *blitAngleOut = SurfaceRotation::Rotated90Degrees; |
107 | *blitFlipYOut = false; |
108 | break; |
109 | case SurfaceRotation::Rotated180Degrees: |
110 | *blitAngleOut = SurfaceRotation::Rotated180Degrees; |
111 | break; |
112 | case SurfaceRotation::Rotated270Degrees: |
113 | *blitAngleOut = SurfaceRotation::Rotated270Degrees; |
114 | *blitFlipYOut = false; |
115 | break; |
116 | default: |
117 | UNREACHABLE(); |
118 | break; |
119 | } |
120 | } |
121 | |
122 | void AdjustBlitAreaForPreRotation(SurfaceRotation framebufferAngle, |
123 | const gl::Rectangle &blitAreaIn, |
124 | const gl::Rectangle &framebufferDimensions, |
125 | gl::Rectangle *blitAreaOut) |
126 | { |
127 | switch (framebufferAngle) |
128 | { |
129 | case SurfaceRotation::Identity: |
130 | // No adjustments needed |
131 | break; |
132 | case SurfaceRotation::Rotated90Degrees: |
133 | blitAreaOut->x = blitAreaIn.y; |
134 | blitAreaOut->y = blitAreaIn.x; |
135 | std::swap(x&: blitAreaOut->width, y&: blitAreaOut->height); |
136 | break; |
137 | case SurfaceRotation::Rotated180Degrees: |
138 | blitAreaOut->x = framebufferDimensions.width - blitAreaIn.x - blitAreaIn.width; |
139 | blitAreaOut->y = framebufferDimensions.height - blitAreaIn.y - blitAreaIn.height; |
140 | break; |
141 | case SurfaceRotation::Rotated270Degrees: |
142 | blitAreaOut->x = framebufferDimensions.height - blitAreaIn.y - blitAreaIn.height; |
143 | blitAreaOut->y = framebufferDimensions.width - blitAreaIn.x - blitAreaIn.width; |
144 | std::swap(x&: blitAreaOut->width, y&: blitAreaOut->height); |
145 | break; |
146 | default: |
147 | UNREACHABLE(); |
148 | break; |
149 | } |
150 | } |
151 | |
152 | void AdjustDimensionsAndFlipForPreRotation(SurfaceRotation framebufferAngle, |
153 | gl::Rectangle *framebufferDimensions, |
154 | bool *flipX, |
155 | bool *flipY) |
156 | { |
157 | switch (framebufferAngle) |
158 | { |
159 | case SurfaceRotation::Identity: |
160 | // No adjustments needed |
161 | break; |
162 | case SurfaceRotation::Rotated90Degrees: |
163 | std::swap(x&: framebufferDimensions->width, y&: framebufferDimensions->height); |
164 | std::swap(x&: *flipX, y&: *flipY); |
165 | break; |
166 | case SurfaceRotation::Rotated180Degrees: |
167 | break; |
168 | case SurfaceRotation::Rotated270Degrees: |
169 | std::swap(x&: framebufferDimensions->width, y&: framebufferDimensions->height); |
170 | std::swap(x&: *flipX, y&: *flipY); |
171 | break; |
172 | default: |
173 | UNREACHABLE(); |
174 | break; |
175 | } |
176 | } |
177 | |
178 | // When blitting, the source and destination areas are viewed like UVs. For example, a 64x64 |
179 | // texture if flipped should have an offset of 64 in either X or Y which corresponds to U or V of 1. |
180 | // On the other hand, when resolving, the source and destination areas are used as fragment |
181 | // coordinates to fetch from. In that case, when flipped, the texture in the above example must |
182 | // have an offset of 63. |
183 | void AdjustBlitResolveParametersForResolve(const gl::Rectangle &sourceArea, |
184 | const gl::Rectangle &destArea, |
185 | UtilsVk::BlitResolveParameters *params) |
186 | { |
187 | params->srcOffset[0] = sourceArea.x; |
188 | params->srcOffset[1] = sourceArea.y; |
189 | params->dstOffset[0] = destArea.x; |
190 | params->dstOffset[1] = destArea.y; |
191 | |
192 | if (sourceArea.isReversedX()) |
193 | { |
194 | ASSERT(sourceArea.x > 0); |
195 | --params->srcOffset[0]; |
196 | } |
197 | if (sourceArea.isReversedY()) |
198 | { |
199 | ASSERT(sourceArea.y > 0); |
200 | --params->srcOffset[1]; |
201 | } |
202 | if (destArea.isReversedX()) |
203 | { |
204 | ASSERT(destArea.x > 0); |
205 | --params->dstOffset[0]; |
206 | } |
207 | if (destArea.isReversedY()) |
208 | { |
209 | ASSERT(destArea.y > 0); |
210 | --params->dstOffset[1]; |
211 | } |
212 | } |
213 | |
214 | // Potentially make adjustments for pre-rotatation. Depending on the angle some of the params need |
215 | // to be swapped and/or changes made to which axis are flipped. |
216 | void AdjustBlitResolveParametersForPreRotation(SurfaceRotation framebufferAngle, |
217 | SurfaceRotation srcFramebufferAngle, |
218 | UtilsVk::BlitResolveParameters *params) |
219 | { |
220 | switch (framebufferAngle) |
221 | { |
222 | case SurfaceRotation::Identity: |
223 | break; |
224 | case SurfaceRotation::Rotated90Degrees: |
225 | std::swap(x&: params->stretch[0], y&: params->stretch[1]); |
226 | std::swap(x&: params->srcOffset[0], y&: params->srcOffset[1]); |
227 | std::swap(x&: params->rotatedOffsetFactor[0], y&: params->rotatedOffsetFactor[1]); |
228 | std::swap(x&: params->flipX, y&: params->flipY); |
229 | if (srcFramebufferAngle == framebufferAngle) |
230 | { |
231 | std::swap(x&: params->dstOffset[0], y&: params->dstOffset[1]); |
232 | std::swap(x&: params->stretch[0], y&: params->stretch[1]); |
233 | } |
234 | break; |
235 | case SurfaceRotation::Rotated180Degrees: |
236 | // Combine flip info with api flip. |
237 | params->flipX = !params->flipX; |
238 | params->flipY = !params->flipY; |
239 | break; |
240 | case SurfaceRotation::Rotated270Degrees: |
241 | std::swap(x&: params->stretch[0], y&: params->stretch[1]); |
242 | std::swap(x&: params->srcOffset[0], y&: params->srcOffset[1]); |
243 | std::swap(x&: params->rotatedOffsetFactor[0], y&: params->rotatedOffsetFactor[1]); |
244 | if (srcFramebufferAngle == framebufferAngle) |
245 | { |
246 | std::swap(x&: params->stretch[0], y&: params->stretch[1]); |
247 | } |
248 | // Combine flip info with api flip. |
249 | params->flipX = !params->flipX; |
250 | params->flipY = !params->flipY; |
251 | std::swap(x&: params->flipX, y&: params->flipY); |
252 | |
253 | break; |
254 | default: |
255 | UNREACHABLE(); |
256 | break; |
257 | } |
258 | } |
259 | |
260 | bool HasResolveAttachment(const gl::AttachmentArray<RenderTargetVk *> &colorRenderTargets, |
261 | const gl::DrawBufferMask &getEnabledDrawBuffers) |
262 | { |
263 | for (size_t colorIndexGL : getEnabledDrawBuffers) |
264 | { |
265 | RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL]; |
266 | if (colorRenderTarget->hasResolveAttachment()) |
267 | { |
268 | return true; |
269 | } |
270 | } |
271 | return false; |
272 | } |
273 | |
274 | vk::FramebufferNonResolveAttachmentMask MakeUnresolveAttachmentMask(const vk::RenderPassDesc &desc) |
275 | { |
276 | vk::FramebufferNonResolveAttachmentMask unresolveMask( |
277 | desc.getColorUnresolveAttachmentMask().bits()); |
278 | if (desc.hasDepthUnresolveAttachment() || desc.hasStencilUnresolveAttachment()) |
279 | { |
280 | // This mask only needs to know if the depth/stencil attachment needs to be unresolved, and |
281 | // is agnostic of the aspect. |
282 | unresolveMask.set(pos: vk::kUnpackedDepthIndex); |
283 | } |
284 | return unresolveMask; |
285 | } |
286 | |
287 | bool IsAnyAttachment3DWithoutAllLayers(const RenderTargetCache<RenderTargetVk> &renderTargetCache, |
288 | gl::DrawBufferMask colorAttachmentsMask, |
289 | uint32_t framebufferLayerCount) |
290 | { |
291 | const auto &colorRenderTargets = renderTargetCache.getColors(); |
292 | for (size_t colorIndexGL : colorAttachmentsMask) |
293 | { |
294 | RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL]; |
295 | ASSERT(colorRenderTarget); |
296 | |
297 | const vk::ImageHelper &image = colorRenderTarget->getImageForRenderPass(); |
298 | |
299 | if (image.getType() == VK_IMAGE_TYPE_3D && image.getExtents().depth > framebufferLayerCount) |
300 | { |
301 | return true; |
302 | } |
303 | } |
304 | |
305 | // Depth/stencil attachments cannot be 3D. |
306 | ASSERT(renderTargetCache.getDepthStencil() == nullptr || |
307 | renderTargetCache.getDepthStencil()->getImageForRenderPass().getType() != |
308 | VK_IMAGE_TYPE_3D); |
309 | |
310 | return false; |
311 | } |
312 | } // anonymous namespace |
313 | |
314 | FramebufferVk::FramebufferVk(RendererVk *renderer, const gl::FramebufferState &state) |
315 | : FramebufferImpl(state), mBackbuffer(nullptr), mActiveColorComponentMasksForClear(0) |
316 | { |
317 | if (mState.isDefault()) |
318 | { |
319 | // These are immutable for system default framebuffer. |
320 | mCurrentFramebufferDesc.updateLayerCount(layerCount: 1); |
321 | mCurrentFramebufferDesc.updateIsMultiview(isMultiview: false); |
322 | } |
323 | |
324 | mIsCurrentFramebufferCached = !renderer->getFeatures().supportsImagelessFramebuffer.enabled; |
325 | } |
326 | |
327 | FramebufferVk::~FramebufferVk() = default; |
328 | |
329 | void FramebufferVk::destroy(const gl::Context *context) |
330 | { |
331 | ContextVk *contextVk = vk::GetImpl(glObject: context); |
332 | releaseCurrentFramebuffer(contextVk); |
333 | } |
334 | |
335 | void FramebufferVk::insertCache(ContextVk *contextVk, |
336 | const vk::FramebufferDesc &desc, |
337 | vk::FramebufferHelper &&newFramebuffer) |
338 | { |
339 | // Add it into per share group cache |
340 | contextVk->getShareGroup()->getFramebufferCache().insert(contextVk, desc, |
341 | framebufferHelper: std::move(newFramebuffer)); |
342 | |
343 | // Create a refcounted cache key object and have each attachment keep a refcount to it so that |
344 | // it can be destroyed promptly if those attachments change. |
345 | const vk::SharedFramebufferCacheKey sharedFramebufferCacheKey = |
346 | vk::CreateSharedFramebufferCacheKey(desc); |
347 | |
348 | // Ask each attachment to hold a reference to the cache so that when any attachment is |
349 | // released, the cache can be destroyed. |
350 | const auto &colorRenderTargets = mRenderTargetCache.getColors(); |
351 | for (size_t colorIndexGL : mState.getColorAttachmentsMask()) |
352 | { |
353 | colorRenderTargets[colorIndexGL]->onNewFramebuffer(sharedFramebufferCacheKey); |
354 | } |
355 | |
356 | if (getDepthStencilRenderTarget()) |
357 | { |
358 | getDepthStencilRenderTarget()->onNewFramebuffer(sharedFramebufferCacheKey); |
359 | } |
360 | } |
361 | |
362 | angle::Result FramebufferVk::discard(const gl::Context *context, |
363 | size_t count, |
364 | const GLenum *attachments) |
365 | { |
366 | return invalidate(context, count, attachments); |
367 | } |
368 | |
369 | angle::Result FramebufferVk::invalidate(const gl::Context *context, |
370 | size_t count, |
371 | const GLenum *attachments) |
372 | { |
373 | ContextVk *contextVk = vk::GetImpl(glObject: context); |
374 | |
375 | ANGLE_TRY(invalidateImpl(contextVk, count, attachments, false, |
376 | getRotatedCompleteRenderArea(contextVk))); |
377 | return angle::Result::Continue; |
378 | } |
379 | |
380 | angle::Result FramebufferVk::invalidateSub(const gl::Context *context, |
381 | size_t count, |
382 | const GLenum *attachments, |
383 | const gl::Rectangle &area) |
384 | { |
385 | ContextVk *contextVk = vk::GetImpl(glObject: context); |
386 | |
387 | const gl::Rectangle nonRotatedCompleteRenderArea = getNonRotatedCompleteRenderArea(); |
388 | gl::Rectangle rotatedInvalidateArea; |
389 | RotateRectangle(rotation: contextVk->getRotationDrawFramebuffer(), |
390 | flipY: contextVk->isViewportFlipEnabledForDrawFBO(), |
391 | framebufferWidth: nonRotatedCompleteRenderArea.width, framebufferHeight: nonRotatedCompleteRenderArea.height, incoming: area, |
392 | outgoing: &rotatedInvalidateArea); |
393 | |
394 | // If invalidateSub() covers the whole framebuffer area, make it behave as invalidate(). |
395 | // The invalidate area is clipped to the render area for use inside invalidateImpl. |
396 | const gl::Rectangle completeRenderArea = getRotatedCompleteRenderArea(contextVk); |
397 | if (ClipRectangle(source: rotatedInvalidateArea, clip: completeRenderArea, intersection: &rotatedInvalidateArea) && |
398 | rotatedInvalidateArea == completeRenderArea) |
399 | { |
400 | return invalidate(context, count, attachments); |
401 | } |
402 | |
403 | // If there are deferred clears, redefer them. syncState may have accumulated deferred clears, |
404 | // but if the framebuffer's attachments are used after this call not through the framebuffer, |
405 | // those clears wouldn't get flushed otherwise (for example as the destination of |
406 | // glCopyTex[Sub]Image, shader storage image, etc). |
407 | redeferClears(contextVk); |
408 | |
409 | if (contextVk->hasActiveRenderPass() && |
410 | rotatedInvalidateArea.encloses(inside: contextVk->getStartedRenderPassCommands().getRenderArea())) |
411 | { |
412 | // Because the render pass's render area is within the invalidated area, it is fine for |
413 | // invalidateImpl() to use a storeOp of DONT_CARE (i.e. fine to not store the contents of |
414 | // the invalidated area). |
415 | ANGLE_TRY(invalidateImpl(contextVk, count, attachments, true, rotatedInvalidateArea)); |
416 | } |
417 | else |
418 | { |
419 | ANGLE_VK_PERF_WARNING( |
420 | contextVk, GL_DEBUG_SEVERITY_LOW, |
421 | "InvalidateSubFramebuffer ignored due to area not covering the render area"); |
422 | } |
423 | |
424 | return angle::Result::Continue; |
425 | } |
426 | |
427 | angle::Result FramebufferVk::clear(const gl::Context *context, GLbitfield mask) |
428 | { |
429 | ANGLE_TRACE_EVENT0("gpu.angle", "FramebufferVk::clear"); |
430 | ContextVk *contextVk = vk::GetImpl(glObject: context); |
431 | |
432 | bool clearColor = IsMaskFlagSet(mask, flag: static_cast<GLbitfield>(GL_COLOR_BUFFER_BIT)); |
433 | bool clearDepth = IsMaskFlagSet(mask, flag: static_cast<GLbitfield>(GL_DEPTH_BUFFER_BIT)); |
434 | bool clearStencil = IsMaskFlagSet(mask, flag: static_cast<GLbitfield>(GL_STENCIL_BUFFER_BIT)); |
435 | gl::DrawBufferMask clearColorBuffers; |
436 | if (clearColor) |
437 | { |
438 | clearColorBuffers = mState.getEnabledDrawBuffers(); |
439 | } |
440 | |
441 | const VkClearColorValue &clearColorValue = contextVk->getClearColorValue().color; |
442 | const VkClearDepthStencilValue &clearDepthStencilValue = |
443 | contextVk->getClearDepthStencilValue().depthStencil; |
444 | |
445 | return clearImpl(context, clearColorBuffers, clearDepth, clearStencil, clearColorValue, |
446 | clearDepthStencilValue); |
447 | } |
448 | |
449 | angle::Result FramebufferVk::clearImpl(const gl::Context *context, |
450 | gl::DrawBufferMask clearColorBuffers, |
451 | bool clearDepth, |
452 | bool clearStencil, |
453 | const VkClearColorValue &clearColorValue, |
454 | const VkClearDepthStencilValue &clearDepthStencilValue) |
455 | { |
456 | ContextVk *contextVk = vk::GetImpl(glObject: context); |
457 | |
458 | const gl::Rectangle scissoredRenderArea = getRotatedScissoredRenderArea(contextVk); |
459 | ASSERT(scissoredRenderArea.width != 0 && scissoredRenderArea.height != 0); |
460 | |
461 | // This function assumes that only enabled attachments are asked to be cleared. |
462 | ASSERT((clearColorBuffers & mState.getEnabledDrawBuffers()) == clearColorBuffers); |
463 | ASSERT(!clearDepth || mState.getDepthAttachment() != nullptr); |
464 | ASSERT(!clearStencil || mState.getStencilAttachment() != nullptr); |
465 | |
466 | gl::BlendStateExt::ColorMaskStorage::Type colorMasks = contextVk->getClearColorMasks(); |
467 | bool clearColor = clearColorBuffers.any(); |
468 | |
469 | // When this function is called, there should always be something to clear. |
470 | ASSERT(clearColor || clearDepth || clearStencil); |
471 | |
472 | const uint8_t stencilMask = |
473 | static_cast<uint8_t>(contextVk->getState().getDepthStencilState().stencilWritemask); |
474 | |
475 | // The front-end should ensure we don't attempt to clear color if all channels are masked. |
476 | ASSERT(!clearColor || colorMasks != 0); |
477 | // The front-end should ensure we don't attempt to clear depth if depth write is disabled. |
478 | ASSERT(!clearDepth || contextVk->getState().getDepthStencilState().depthMask); |
479 | // The front-end should ensure we don't attempt to clear stencil if all bits are masked. |
480 | ASSERT(!clearStencil || stencilMask != 0); |
481 | |
482 | // Make sure to close the render pass now if in read-only depth/stencil feedback loop mode and |
483 | // depth/stencil is being cleared. |
484 | if (clearDepth || clearStencil) |
485 | { |
486 | ANGLE_TRY(contextVk->updateRenderPassDepthFeedbackLoopMode( |
487 | clearDepth ? UpdateDepthFeedbackLoopReason::Clear : UpdateDepthFeedbackLoopReason::None, |
488 | clearStencil ? UpdateDepthFeedbackLoopReason::Clear |
489 | : UpdateDepthFeedbackLoopReason::None)); |
490 | } |
491 | |
492 | const bool scissoredClear = scissoredRenderArea != getRotatedCompleteRenderArea(contextVk); |
493 | |
494 | // We use the draw path if scissored clear, or color or stencil are masked. Note that depth |
495 | // clearing is already disabled if there's a depth mask. |
496 | const bool maskedClearColor = clearColor && (mActiveColorComponentMasksForClear & colorMasks) != |
497 | mActiveColorComponentMasksForClear; |
498 | const bool maskedClearStencil = clearStencil && stencilMask != 0xFF; |
499 | |
500 | bool clearColorWithDraw = clearColor && (maskedClearColor || scissoredClear); |
501 | bool clearDepthWithDraw = clearDepth && scissoredClear; |
502 | bool clearStencilWithDraw = clearStencil && (maskedClearStencil || scissoredClear); |
503 | |
504 | const bool isMidRenderPassClear = |
505 | contextVk->hasStartedRenderPassWithQueueSerial(queueSerial: mLastRenderPassQueueSerial) && |
506 | !contextVk->getStartedRenderPassCommands().getCommandBuffer().empty(); |
507 | if (isMidRenderPassClear) |
508 | { |
509 | // Emit debug-util markers for this mid-render-pass clear |
510 | ANGLE_TRY( |
511 | contextVk->handleGraphicsEventLog(rx::GraphicsEventCmdBuf::InRenderPassCmdBufQueryCmd)); |
512 | } |
513 | else |
514 | { |
515 | ASSERT(!contextVk->hasActiveRenderPass() || |
516 | contextVk->hasStartedRenderPassWithQueueSerial(mLastRenderPassQueueSerial)); |
517 | // Emit debug-util markers for this outside-render-pass clear |
518 | ANGLE_TRY( |
519 | contextVk->handleGraphicsEventLog(rx::GraphicsEventCmdBuf::InOutsideCmdBufQueryCmd)); |
520 | } |
521 | |
522 | const bool preferDrawOverClearAttachments = |
523 | contextVk->getRenderer()->getFeatures().preferDrawClearOverVkCmdClearAttachments.enabled; |
524 | |
525 | // Merge current clears with the deferred clears, then proceed with only processing deferred |
526 | // clears. This simplifies the clear paths such that they don't need to consider both the |
527 | // current and deferred clears. Additionally, it avoids needing to undo an unresolve |
528 | // operation; say attachment A is deferred cleared and multisampled-render-to-texture |
529 | // attachment B is currently cleared. Assuming a render pass needs to start (because for |
530 | // example attachment C needs to clear with a draw path), starting one with only deferred |
531 | // clears and then applying the current clears won't work as attachment B is unresolved, and |
532 | // there are no facilities to undo that. |
533 | if (preferDrawOverClearAttachments && isMidRenderPassClear) |
534 | { |
535 | // On buggy hardware, prefer to clear with a draw call instead of vkCmdClearAttachments. |
536 | // Note that it's impossible to have deferred clears in the middle of the render pass. |
537 | ASSERT(!mDeferredClears.any()); |
538 | |
539 | clearColorWithDraw = clearColor; |
540 | clearDepthWithDraw = clearDepth; |
541 | clearStencilWithDraw = clearStencil; |
542 | } |
543 | else |
544 | { |
545 | gl::DrawBufferMask clearColorDrawBuffersMask; |
546 | if (clearColor && !clearColorWithDraw) |
547 | { |
548 | clearColorDrawBuffersMask = clearColorBuffers; |
549 | } |
550 | |
551 | mergeClearsWithDeferredClears(clearColorBuffers: clearColorDrawBuffersMask, clearDepth: clearDepth && !clearDepthWithDraw, |
552 | clearStencil: clearStencil && !clearStencilWithDraw, clearColorValue, |
553 | clearDepthStencilValue); |
554 | } |
555 | |
556 | // If any deferred clears, we can further defer them, clear them with vkCmdClearAttachments or |
557 | // flush them if necessary. |
558 | if (mDeferredClears.any()) |
559 | { |
560 | const bool clearAnyWithDraw = |
561 | clearColorWithDraw || clearDepthWithDraw || clearStencilWithDraw; |
562 | |
563 | bool isAnyAttachment3DWithoutAllLayers = |
564 | IsAnyAttachment3DWithoutAllLayers(renderTargetCache: mRenderTargetCache, colorAttachmentsMask: mState.getColorAttachmentsMask(), |
565 | framebufferLayerCount: mCurrentFramebufferDesc.getLayerCount()); |
566 | |
567 | // If we are in an active renderpass that has recorded commands and the framebuffer hasn't |
568 | // changed, inline the clear. |
569 | if (isMidRenderPassClear) |
570 | { |
571 | ANGLE_VK_PERF_WARNING( |
572 | contextVk, GL_DEBUG_SEVERITY_LOW, |
573 | "Clear effectively discarding previous draw call results. Suggest earlier Clear " |
574 | "followed by masked color or depth/stencil draw calls instead, or " |
575 | "glInvalidateFramebuffer to discard data instead"); |
576 | |
577 | ASSERT(!preferDrawOverClearAttachments); |
578 | |
579 | // clearWithCommand will operate on deferred clears. |
580 | clearWithCommand(contextVk, scissoredRenderArea, behavior: ClearWithCommand::OptimizeWithLoadOp, |
581 | clears: &mDeferredClears); |
582 | |
583 | // clearWithCommand will clear only those attachments that have been used in the render |
584 | // pass, and removes them from mDeferredClears. Any deferred clears that are left can |
585 | // be performed with a renderpass loadOp. |
586 | if (mDeferredClears.any()) |
587 | { |
588 | clearWithLoadOp(contextVk); |
589 | } |
590 | } |
591 | else |
592 | { |
593 | if (contextVk->hasActiveRenderPass()) |
594 | { |
595 | // Typically, clears are deferred such that it's impossible to have a render pass |
596 | // opened without any additional commands recorded on it. This is not true for some |
597 | // corner cases, such as with 3D or external attachments. In those cases, a clear |
598 | // can open a render pass that's otherwise empty, and additional clears can continue |
599 | // to be accumulated in the render pass loadOps. |
600 | ASSERT(isAnyAttachment3DWithoutAllLayers || hasAnyExternalAttachments()); |
601 | clearWithLoadOp(contextVk); |
602 | } |
603 | |
604 | // This path will defer the current clears along with deferred clears. This won't work |
605 | // if any attachment needs to be subsequently cleared with a draw call. In that case, |
606 | // flush deferred clears, which will start a render pass with deferred clear values. |
607 | // The subsequent draw call will then operate on the cleared attachments. |
608 | // |
609 | // Additionally, if the framebuffer is layered, any attachment is 3D and it has a larger |
610 | // depth than the framebuffer layers, clears cannot be deferred. This is because the |
611 | // clear may later need to be flushed with vkCmdClearColorImage, which cannot partially |
612 | // clear the 3D texture. In that case, the clears are flushed immediately too. |
613 | // |
614 | // For external images such as from AHBs, the clears are not deferred so that they are |
615 | // definitely applied before the application uses them outside of the control of ANGLE. |
616 | if (clearAnyWithDraw || isAnyAttachment3DWithoutAllLayers || |
617 | hasAnyExternalAttachments()) |
618 | { |
619 | ANGLE_TRY(flushDeferredClears(contextVk)); |
620 | } |
621 | else |
622 | { |
623 | redeferClears(contextVk); |
624 | } |
625 | } |
626 | |
627 | // If nothing left to clear, early out. |
628 | if (!clearAnyWithDraw) |
629 | { |
630 | ASSERT(mDeferredClears.empty()); |
631 | return angle::Result::Continue; |
632 | } |
633 | } |
634 | |
635 | if (!clearColorWithDraw) |
636 | { |
637 | clearColorBuffers.reset(); |
638 | } |
639 | |
640 | // If we reach here simply because the clear is scissored (as opposed to masked), use |
641 | // vkCmdClearAttachments to clear the attachments. The attachments that are masked will |
642 | // continue to use a draw call. For depth, vkCmdClearAttachments can always be used, and no |
643 | // shader/pipeline support would then be required (though this is pending removal of the |
644 | // preferDrawOverClearAttachments workaround). |
645 | // |
646 | // A potential optimization is to use loadOp=Clear for scissored clears, but care needs to be |
647 | // taken to either break the render pass on growRenderArea(), or to turn the op back to Load and |
648 | // revert to vkCmdClearAttachments. This is not currently deemed necessary. |
649 | if (((clearColorBuffers.any() && !mEmulatedAlphaAttachmentMask.any() && !maskedClearColor) || |
650 | clearDepthWithDraw || (clearStencilWithDraw && !maskedClearStencil)) && |
651 | !preferDrawOverClearAttachments) |
652 | { |
653 | if (!contextVk->hasActiveRenderPass()) |
654 | { |
655 | // Start a new render pass if necessary to record the commands. |
656 | vk::RenderPassCommandBuffer *commandBuffer; |
657 | gl::Rectangle renderArea = getRenderArea(contextVk); |
658 | ANGLE_TRY(contextVk->startRenderPass(renderArea, &commandBuffer, nullptr)); |
659 | } |
660 | |
661 | // Build clear values |
662 | vk::ClearValuesArray clears; |
663 | if (!maskedClearColor && !mEmulatedAlphaAttachmentMask.any()) |
664 | { |
665 | VkClearValue colorClearValue = {}; |
666 | colorClearValue.color = clearColorValue; |
667 | for (size_t colorIndexGL : clearColorBuffers) |
668 | { |
669 | clears.store(index: static_cast<uint32_t>(colorIndexGL), aspectFlags: VK_IMAGE_ASPECT_COLOR_BIT, |
670 | clearValue: colorClearValue); |
671 | } |
672 | clearColorBuffers.reset(); |
673 | } |
674 | VkImageAspectFlags dsAspectFlags = 0; |
675 | if (clearDepthWithDraw) |
676 | { |
677 | dsAspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT; |
678 | clearDepthWithDraw = false; |
679 | } |
680 | if (clearStencilWithDraw && !maskedClearStencil) |
681 | { |
682 | dsAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; |
683 | clearStencilWithDraw = false; |
684 | } |
685 | if (dsAspectFlags != 0) |
686 | { |
687 | VkClearValue dsClearValue = {}; |
688 | dsClearValue.depthStencil = clearDepthStencilValue; |
689 | clears.store(index: vk::kUnpackedDepthIndex, aspectFlags: dsAspectFlags, clearValue: dsClearValue); |
690 | } |
691 | |
692 | clearWithCommand(contextVk, scissoredRenderArea, behavior: ClearWithCommand::Always, clears: &clears); |
693 | |
694 | if (!clearColorBuffers.any() && !clearStencilWithDraw) |
695 | { |
696 | ASSERT(!clearDepthWithDraw); |
697 | return angle::Result::Continue; |
698 | } |
699 | } |
700 | |
701 | // The most costly clear mode is when we need to mask out specific color channels or stencil |
702 | // bits. This can only be done with a draw call. |
703 | return clearWithDraw(contextVk, clearArea: scissoredRenderArea, clearColorBuffers, clearDepth: clearDepthWithDraw, |
704 | clearStencil: clearStencilWithDraw, colorMasks, stencilMask, clearColorValue, |
705 | clearDepthStencilValue); |
706 | } |
707 | |
708 | angle::Result FramebufferVk::clearBufferfv(const gl::Context *context, |
709 | GLenum buffer, |
710 | GLint drawbuffer, |
711 | const GLfloat *values) |
712 | { |
713 | VkClearValue clearValue = {}; |
714 | |
715 | bool clearDepth = false; |
716 | gl::DrawBufferMask clearColorBuffers; |
717 | |
718 | if (buffer == GL_DEPTH) |
719 | { |
720 | clearDepth = true; |
721 | clearValue.depthStencil.depth = values[0]; |
722 | } |
723 | else |
724 | { |
725 | clearColorBuffers.set(pos: drawbuffer); |
726 | clearValue.color.float32[0] = values[0]; |
727 | clearValue.color.float32[1] = values[1]; |
728 | clearValue.color.float32[2] = values[2]; |
729 | clearValue.color.float32[3] = values[3]; |
730 | } |
731 | |
732 | return clearImpl(context, clearColorBuffers, clearDepth, clearStencil: false, clearColorValue: clearValue.color, |
733 | clearDepthStencilValue: clearValue.depthStencil); |
734 | } |
735 | |
736 | angle::Result FramebufferVk::clearBufferuiv(const gl::Context *context, |
737 | GLenum buffer, |
738 | GLint drawbuffer, |
739 | const GLuint *values) |
740 | { |
741 | VkClearValue clearValue = {}; |
742 | |
743 | gl::DrawBufferMask clearColorBuffers; |
744 | clearColorBuffers.set(pos: drawbuffer); |
745 | |
746 | clearValue.color.uint32[0] = values[0]; |
747 | clearValue.color.uint32[1] = values[1]; |
748 | clearValue.color.uint32[2] = values[2]; |
749 | clearValue.color.uint32[3] = values[3]; |
750 | |
751 | return clearImpl(context, clearColorBuffers, clearDepth: false, clearStencil: false, clearColorValue: clearValue.color, |
752 | clearDepthStencilValue: clearValue.depthStencil); |
753 | } |
754 | |
755 | angle::Result FramebufferVk::clearBufferiv(const gl::Context *context, |
756 | GLenum buffer, |
757 | GLint drawbuffer, |
758 | const GLint *values) |
759 | { |
760 | VkClearValue clearValue = {}; |
761 | |
762 | bool clearStencil = false; |
763 | gl::DrawBufferMask clearColorBuffers; |
764 | |
765 | if (buffer == GL_STENCIL) |
766 | { |
767 | clearStencil = true; |
768 | clearValue.depthStencil.stencil = static_cast<uint8_t>(values[0]); |
769 | } |
770 | else |
771 | { |
772 | clearColorBuffers.set(pos: drawbuffer); |
773 | clearValue.color.int32[0] = values[0]; |
774 | clearValue.color.int32[1] = values[1]; |
775 | clearValue.color.int32[2] = values[2]; |
776 | clearValue.color.int32[3] = values[3]; |
777 | } |
778 | |
779 | return clearImpl(context, clearColorBuffers, clearDepth: false, clearStencil, clearColorValue: clearValue.color, |
780 | clearDepthStencilValue: clearValue.depthStencil); |
781 | } |
782 | |
783 | angle::Result FramebufferVk::clearBufferfi(const gl::Context *context, |
784 | GLenum buffer, |
785 | GLint drawbuffer, |
786 | GLfloat depth, |
787 | GLint stencil) |
788 | { |
789 | VkClearValue clearValue = {}; |
790 | |
791 | clearValue.depthStencil.depth = depth; |
792 | clearValue.depthStencil.stencil = static_cast<uint8_t>(stencil); |
793 | |
794 | return clearImpl(context, clearColorBuffers: gl::DrawBufferMask(), clearDepth: true, clearStencil: true, clearColorValue: clearValue.color, |
795 | clearDepthStencilValue: clearValue.depthStencil); |
796 | } |
797 | |
798 | const gl::InternalFormat &FramebufferVk::getImplementationColorReadFormat( |
799 | const gl::Context *context) const |
800 | { |
801 | ContextVk *contextVk = vk::GetImpl(glObject: context); |
802 | GLenum sizedFormat = mState.getReadAttachment()->getFormat().info->sizedInternalFormat; |
803 | const vk::Format &vkFormat = contextVk->getRenderer()->getFormat(internalFormat: sizedFormat); |
804 | GLenum implFormat = vkFormat.getActualRenderableImageFormat().fboImplementationInternalFormat; |
805 | return gl::GetSizedInternalFormatInfo(internalFormat: implFormat); |
806 | } |
807 | |
808 | angle::Result FramebufferVk::readPixels(const gl::Context *context, |
809 | const gl::Rectangle &area, |
810 | GLenum format, |
811 | GLenum type, |
812 | const gl::PixelPackState &pack, |
813 | gl::Buffer *packBuffer, |
814 | void *pixels) |
815 | { |
816 | // Clip read area to framebuffer. |
817 | const gl::Extents &fbSize = getState().getReadPixelsAttachment(readFormat: format)->getSize(); |
818 | const gl::Rectangle fbRect(0, 0, fbSize.width, fbSize.height); |
819 | ContextVk *contextVk = vk::GetImpl(glObject: context); |
820 | |
821 | gl::Rectangle clippedArea; |
822 | if (!ClipRectangle(source: area, clip: fbRect, intersection: &clippedArea)) |
823 | { |
824 | // nothing to read |
825 | return angle::Result::Continue; |
826 | } |
827 | |
828 | // Flush any deferred clears. |
829 | ANGLE_TRY(flushDeferredClears(contextVk)); |
830 | |
831 | GLuint outputSkipBytes = 0; |
832 | PackPixelsParams params; |
833 | ANGLE_TRY(vk::ImageHelper::GetReadPixelsParams(contextVk, pack, packBuffer, format, type, area, |
834 | clippedArea, ¶ms, &outputSkipBytes)); |
835 | |
836 | bool flipY = contextVk->isViewportFlipEnabledForReadFBO(); |
837 | switch (params.rotation = contextVk->getRotationReadFramebuffer()) |
838 | { |
839 | case SurfaceRotation::Identity: |
840 | // Do not rotate gl_Position (surface matches the device's orientation): |
841 | if (flipY) |
842 | { |
843 | params.area.y = fbRect.height - clippedArea.y - clippedArea.height; |
844 | } |
845 | break; |
846 | case SurfaceRotation::Rotated90Degrees: |
847 | // Rotate gl_Position 90 degrees: |
848 | params.area.x = clippedArea.y; |
849 | params.area.y = |
850 | flipY ? clippedArea.x : fbRect.width - clippedArea.x - clippedArea.width; |
851 | std::swap(x&: params.area.width, y&: params.area.height); |
852 | break; |
853 | case SurfaceRotation::Rotated180Degrees: |
854 | // Rotate gl_Position 180 degrees: |
855 | params.area.x = fbRect.width - clippedArea.x - clippedArea.width; |
856 | params.area.y = |
857 | flipY ? clippedArea.y : fbRect.height - clippedArea.y - clippedArea.height; |
858 | break; |
859 | case SurfaceRotation::Rotated270Degrees: |
860 | // Rotate gl_Position 270 degrees: |
861 | params.area.x = fbRect.height - clippedArea.y - clippedArea.height; |
862 | params.area.y = |
863 | flipY ? fbRect.width - clippedArea.x - clippedArea.width : clippedArea.x; |
864 | std::swap(x&: params.area.width, y&: params.area.height); |
865 | break; |
866 | default: |
867 | UNREACHABLE(); |
868 | break; |
869 | } |
870 | if (flipY) |
871 | { |
872 | params.reverseRowOrder = !params.reverseRowOrder; |
873 | } |
874 | |
875 | ANGLE_TRY(readPixelsImpl(contextVk, params.area, params, getReadPixelsAspectFlags(format), |
876 | getReadPixelsRenderTarget(format), |
877 | static_cast<uint8_t *>(pixels) + outputSkipBytes)); |
878 | return angle::Result::Continue; |
879 | } |
880 | |
881 | RenderTargetVk *FramebufferVk::getDepthStencilRenderTarget() const |
882 | { |
883 | return mRenderTargetCache.getDepthStencil(); |
884 | } |
885 | |
886 | RenderTargetVk *FramebufferVk::getColorDrawRenderTarget(size_t colorIndexGL) const |
887 | { |
888 | RenderTargetVk *renderTarget = mRenderTargetCache.getColorDraw(state: mState, colorIndex: colorIndexGL); |
889 | ASSERT(renderTarget && renderTarget->getImageForRenderPass().valid()); |
890 | return renderTarget; |
891 | } |
892 | |
893 | RenderTargetVk *FramebufferVk::getColorReadRenderTarget() const |
894 | { |
895 | RenderTargetVk *renderTarget = mRenderTargetCache.getColorRead(state: mState); |
896 | ASSERT(renderTarget && renderTarget->getImageForRenderPass().valid()); |
897 | return renderTarget; |
898 | } |
899 | |
900 | RenderTargetVk *FramebufferVk::getReadPixelsRenderTarget(GLenum format) const |
901 | { |
902 | switch (format) |
903 | { |
904 | case GL_DEPTH_COMPONENT: |
905 | case GL_STENCIL_INDEX_OES: |
906 | case GL_DEPTH_STENCIL_OES: |
907 | return getDepthStencilRenderTarget(); |
908 | default: |
909 | return getColorReadRenderTarget(); |
910 | } |
911 | } |
912 | |
913 | VkImageAspectFlagBits FramebufferVk::getReadPixelsAspectFlags(GLenum format) const |
914 | { |
915 | switch (format) |
916 | { |
917 | case GL_DEPTH_COMPONENT: |
918 | return VK_IMAGE_ASPECT_DEPTH_BIT; |
919 | case GL_STENCIL_INDEX_OES: |
920 | return VK_IMAGE_ASPECT_STENCIL_BIT; |
921 | case GL_DEPTH_STENCIL_OES: |
922 | return vk::IMAGE_ASPECT_DEPTH_STENCIL; |
923 | default: |
924 | return VK_IMAGE_ASPECT_COLOR_BIT; |
925 | } |
926 | } |
927 | |
928 | angle::Result FramebufferVk::blitWithCommand(ContextVk *contextVk, |
929 | const gl::Rectangle &sourceArea, |
930 | const gl::Rectangle &destArea, |
931 | RenderTargetVk *readRenderTarget, |
932 | RenderTargetVk *drawRenderTarget, |
933 | GLenum filter, |
934 | bool colorBlit, |
935 | bool depthBlit, |
936 | bool stencilBlit, |
937 | bool flipX, |
938 | bool flipY) |
939 | { |
940 | // Since blitRenderbufferRect is called for each render buffer that needs to be blitted, |
941 | // it should never be the case that both color and depth/stencil need to be blitted at |
942 | // at the same time. |
943 | ASSERT(colorBlit != (depthBlit || stencilBlit)); |
944 | |
945 | vk::ImageHelper *srcImage = &readRenderTarget->getImageForCopy(); |
946 | vk::ImageHelper *dstImage = &drawRenderTarget->getImageForWrite(); |
947 | |
948 | VkImageAspectFlags imageAspectMask = srcImage->getAspectFlags(); |
949 | VkImageAspectFlags blitAspectMask = imageAspectMask; |
950 | |
951 | // Remove depth or stencil aspects if they are not requested to be blitted. |
952 | if (!depthBlit) |
953 | { |
954 | blitAspectMask &= ~VK_IMAGE_ASPECT_DEPTH_BIT; |
955 | } |
956 | if (!stencilBlit) |
957 | { |
958 | blitAspectMask &= ~VK_IMAGE_ASPECT_STENCIL_BIT; |
959 | } |
960 | |
961 | vk::CommandBufferAccess access; |
962 | access.onImageTransferRead(aspectFlags: imageAspectMask, image: srcImage); |
963 | access.onImageTransferWrite(levelStart: drawRenderTarget->getLevelIndex(), levelCount: 1, |
964 | layerStart: drawRenderTarget->getLayerIndex(), layerCount: 1, aspectFlags: imageAspectMask, image: dstImage); |
965 | vk::OutsideRenderPassCommandBuffer *commandBuffer; |
966 | ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer)); |
967 | |
968 | VkImageBlit blit = {}; |
969 | blit.srcSubresource.aspectMask = blitAspectMask; |
970 | blit.srcSubresource.mipLevel = srcImage->toVkLevel(levelIndexGL: readRenderTarget->getLevelIndex()).get(); |
971 | blit.srcSubresource.baseArrayLayer = readRenderTarget->getLayerIndex(); |
972 | blit.srcSubresource.layerCount = 1; |
973 | blit.srcOffsets[0] = {.x: sourceArea.x0(), .y: sourceArea.y0(), .z: 0}; |
974 | blit.srcOffsets[1] = {.x: sourceArea.x1(), .y: sourceArea.y1(), .z: 1}; |
975 | blit.dstSubresource.aspectMask = blitAspectMask; |
976 | blit.dstSubresource.mipLevel = dstImage->toVkLevel(levelIndexGL: drawRenderTarget->getLevelIndex()).get(); |
977 | blit.dstSubresource.baseArrayLayer = drawRenderTarget->getLayerIndex(); |
978 | blit.dstSubresource.layerCount = 1; |
979 | blit.dstOffsets[0] = {.x: destArea.x0(), .y: destArea.y0(), .z: 0}; |
980 | blit.dstOffsets[1] = {.x: destArea.x1(), .y: destArea.y1(), .z: 1}; |
981 | |
982 | commandBuffer->blitImage(srcImage: srcImage->getImage(), srcImageLayout: VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, |
983 | dstImage: dstImage->getImage(), dstImageLayout: VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, regionCount: 1, regions: &blit, |
984 | filter: gl_vk::GetFilter(filter)); |
985 | |
986 | return angle::Result::Continue; |
987 | } |
988 | |
989 | angle::Result FramebufferVk::blit(const gl::Context *context, |
990 | const gl::Rectangle &sourceAreaIn, |
991 | const gl::Rectangle &destAreaIn, |
992 | GLbitfield mask, |
993 | GLenum filter) |
994 | { |
995 | ContextVk *contextVk = vk::GetImpl(glObject: context); |
996 | RendererVk *renderer = contextVk->getRenderer(); |
997 | UtilsVk &utilsVk = contextVk->getUtils(); |
998 | |
999 | // If any clears were picked up when syncing the read framebuffer (as the blit source), redefer |
1000 | // them. They correspond to attachments that are not used in the blit. This will cause the |
1001 | // read framebuffer to become dirty, so the attachments will be synced again on the next command |
1002 | // that might be using them. |
1003 | const gl::State &glState = contextVk->getState(); |
1004 | const gl::Framebuffer *srcFramebuffer = glState.getReadFramebuffer(); |
1005 | FramebufferVk *srcFramebufferVk = vk::GetImpl(glObject: srcFramebuffer); |
1006 | if (srcFramebufferVk->mDeferredClears.any()) |
1007 | { |
1008 | srcFramebufferVk->redeferClearsForReadFramebuffer(contextVk); |
1009 | } |
1010 | |
1011 | // We can sometimes end up in a blit with some clear commands saved. Ensure all clear commands |
1012 | // are issued before we issue the blit command. |
1013 | ANGLE_TRY(flushDeferredClears(contextVk)); |
1014 | |
1015 | const bool blitColorBuffer = (mask & GL_COLOR_BUFFER_BIT) != 0; |
1016 | const bool blitDepthBuffer = (mask & GL_DEPTH_BUFFER_BIT) != 0; |
1017 | const bool blitStencilBuffer = (mask & GL_STENCIL_BUFFER_BIT) != 0; |
1018 | |
1019 | // If a framebuffer contains a mixture of multisampled and multisampled-render-to-texture |
1020 | // attachments, this function could be simultaneously doing a blit on one attachment and resolve |
1021 | // on another. For the most part, this means resolve semantics apply. However, as the resolve |
1022 | // path cannot be taken for multisampled-render-to-texture attachments, the distinction of |
1023 | // whether resolve is done for each attachment or blit is made. |
1024 | const bool isColorResolve = |
1025 | blitColorBuffer && |
1026 | srcFramebufferVk->getColorReadRenderTarget()->getImageForCopy().getSamples() > 1; |
1027 | const bool isDepthStencilResolve = |
1028 | (blitDepthBuffer || blitStencilBuffer) && |
1029 | srcFramebufferVk->getDepthStencilRenderTarget()->getImageForCopy().getSamples() > 1; |
1030 | const bool isResolve = isColorResolve || isDepthStencilResolve; |
1031 | |
1032 | bool srcFramebufferFlippedY = contextVk->isViewportFlipEnabledForReadFBO(); |
1033 | bool dstFramebufferFlippedY = contextVk->isViewportFlipEnabledForDrawFBO(); |
1034 | |
1035 | gl::Rectangle sourceArea = sourceAreaIn; |
1036 | gl::Rectangle destArea = destAreaIn; |
1037 | |
1038 | // Note: GLES (all 3.x versions) require source and destination area to be identical when |
1039 | // resolving. |
1040 | ASSERT(!isResolve || |
1041 | (sourceArea.x == destArea.x && sourceArea.y == destArea.y && |
1042 | sourceArea.width == destArea.width && sourceArea.height == destArea.height)); |
1043 | |
1044 | gl::Rectangle srcFramebufferDimensions = srcFramebufferVk->getNonRotatedCompleteRenderArea(); |
1045 | gl::Rectangle dstFramebufferDimensions = getNonRotatedCompleteRenderArea(); |
1046 | |
1047 | // If the destination is flipped in either direction, we will flip the source instead so that |
1048 | // the destination area is always unflipped. |
1049 | sourceArea = sourceArea.flip(flipX: destArea.isReversedX(), flipY: destArea.isReversedY()); |
1050 | destArea = destArea.removeReversal(); |
1051 | |
1052 | // Calculate the stretch factor prior to any clipping, as it needs to remain constant. |
1053 | const double stretch[2] = { |
1054 | std::abs(lcpp_x: sourceArea.width / static_cast<double>(destArea.width)), |
1055 | std::abs(lcpp_x: sourceArea.height / static_cast<double>(destArea.height)), |
1056 | }; |
1057 | |
1058 | // Potentially make adjustments for pre-rotatation. To handle various cases (e.g. clipping) |
1059 | // and to not interrupt the normal flow of the code, different adjustments are made in |
1060 | // different parts of the code. These first adjustments are for whether or not to flip the |
1061 | // y-axis, and to note the overall rotation (regardless of whether it is the source or |
1062 | // destination that is rotated). |
1063 | SurfaceRotation srcFramebufferRotation = contextVk->getRotationReadFramebuffer(); |
1064 | SurfaceRotation dstFramebufferRotation = contextVk->getRotationDrawFramebuffer(); |
1065 | SurfaceRotation rotation = SurfaceRotation::Identity; |
1066 | // Both the source and destination cannot be rotated (which would indicate both are the default |
1067 | // framebuffer (i.e. swapchain image). |
1068 | ASSERT((srcFramebufferRotation == SurfaceRotation::Identity) || |
1069 | (dstFramebufferRotation == SurfaceRotation::Identity)); |
1070 | EarlyAdjustFlipYForPreRotation(blitAngleIn: srcFramebufferRotation, blitAngleOut: &rotation, blitFlipYOut: &srcFramebufferFlippedY); |
1071 | EarlyAdjustFlipYForPreRotation(blitAngleIn: dstFramebufferRotation, blitAngleOut: &rotation, blitFlipYOut: &dstFramebufferFlippedY); |
1072 | |
1073 | // First, clip the source area to framebuffer. That requires transforming the destination area |
1074 | // to match the clipped source. |
1075 | gl::Rectangle absSourceArea = sourceArea.removeReversal(); |
1076 | gl::Rectangle clippedSourceArea; |
1077 | if (!gl::ClipRectangle(source: srcFramebufferDimensions, clip: absSourceArea, intersection: &clippedSourceArea)) |
1078 | { |
1079 | return angle::Result::Continue; |
1080 | } |
1081 | |
1082 | // Resize the destination area based on the new size of source. Note again that stretch is |
1083 | // calculated as SrcDimension/DestDimension. |
1084 | gl::Rectangle srcClippedDestArea; |
1085 | if (isResolve) |
1086 | { |
1087 | // Source and destination areas are identical in resolve (except rotate it, if appropriate). |
1088 | srcClippedDestArea = clippedSourceArea; |
1089 | AdjustBlitAreaForPreRotation(framebufferAngle: dstFramebufferRotation, blitAreaIn: clippedSourceArea, |
1090 | framebufferDimensions: dstFramebufferDimensions, blitAreaOut: &srcClippedDestArea); |
1091 | } |
1092 | else if (clippedSourceArea == absSourceArea) |
1093 | { |
1094 | // If there was no clipping, keep destination area as is (except rotate it, if appropriate). |
1095 | srcClippedDestArea = destArea; |
1096 | AdjustBlitAreaForPreRotation(framebufferAngle: dstFramebufferRotation, blitAreaIn: destArea, framebufferDimensions: dstFramebufferDimensions, |
1097 | blitAreaOut: &srcClippedDestArea); |
1098 | } |
1099 | else |
1100 | { |
1101 | // Shift destination area's x0,y0,x1,y1 by as much as the source area's got shifted (taking |
1102 | // stretching into account). Note that double is used as float doesn't have enough |
1103 | // precision near the end of int range. |
1104 | double x0Shift = std::round(x: (clippedSourceArea.x - absSourceArea.x) / stretch[0]); |
1105 | double y0Shift = std::round(x: (clippedSourceArea.y - absSourceArea.y) / stretch[1]); |
1106 | double x1Shift = std::round(x: (absSourceArea.x1() - clippedSourceArea.x1()) / stretch[0]); |
1107 | double y1Shift = std::round(x: (absSourceArea.y1() - clippedSourceArea.y1()) / stretch[1]); |
1108 | |
1109 | // If the source area was reversed in any direction, the shift should be applied in the |
1110 | // opposite direction as well. |
1111 | if (sourceArea.isReversedX()) |
1112 | { |
1113 | std::swap(x&: x0Shift, y&: x1Shift); |
1114 | } |
1115 | |
1116 | if (sourceArea.isReversedY()) |
1117 | { |
1118 | std::swap(x&: y0Shift, y&: y1Shift); |
1119 | } |
1120 | |
1121 | srcClippedDestArea.x = destArea.x0() + static_cast<int>(x0Shift); |
1122 | srcClippedDestArea.y = destArea.y0() + static_cast<int>(y0Shift); |
1123 | int x1 = destArea.x1() - static_cast<int>(x1Shift); |
1124 | int y1 = destArea.y1() - static_cast<int>(y1Shift); |
1125 | |
1126 | srcClippedDestArea.width = x1 - srcClippedDestArea.x; |
1127 | srcClippedDestArea.height = y1 - srcClippedDestArea.y; |
1128 | |
1129 | // Rotate srcClippedDestArea if the destination is rotated |
1130 | if (dstFramebufferRotation != SurfaceRotation::Identity) |
1131 | { |
1132 | gl::Rectangle originalSrcClippedDestArea = srcClippedDestArea; |
1133 | AdjustBlitAreaForPreRotation(framebufferAngle: dstFramebufferRotation, blitAreaIn: originalSrcClippedDestArea, |
1134 | framebufferDimensions: dstFramebufferDimensions, blitAreaOut: &srcClippedDestArea); |
1135 | } |
1136 | } |
1137 | |
1138 | // If framebuffers are flipped in Y, flip the source and destination area (which define the |
1139 | // transformation regardless of clipping), as well as the blit area (which is the clipped |
1140 | // destination area). |
1141 | if (srcFramebufferFlippedY) |
1142 | { |
1143 | sourceArea.y = srcFramebufferDimensions.height - sourceArea.y; |
1144 | sourceArea.height = -sourceArea.height; |
1145 | } |
1146 | if (dstFramebufferFlippedY) |
1147 | { |
1148 | destArea.y = dstFramebufferDimensions.height - destArea.y; |
1149 | destArea.height = -destArea.height; |
1150 | |
1151 | srcClippedDestArea.y = |
1152 | dstFramebufferDimensions.height - srcClippedDestArea.y - srcClippedDestArea.height; |
1153 | } |
1154 | |
1155 | bool flipX = sourceArea.isReversedX() != destArea.isReversedX(); |
1156 | bool flipY = sourceArea.isReversedY() != destArea.isReversedY(); |
1157 | |
1158 | // GLES doesn't allow flipping the parameters of glBlitFramebuffer if performing a resolve. |
1159 | ASSERT(!isResolve || |
1160 | (flipX == false && flipY == (srcFramebufferFlippedY != dstFramebufferFlippedY))); |
1161 | |
1162 | // Again, transfer the destination flip to source, so destination is unflipped. Note that |
1163 | // destArea was not reversed until the final possible Y-flip. |
1164 | ASSERT(!destArea.isReversedX()); |
1165 | sourceArea = sourceArea.flip(flipX: false, flipY: destArea.isReversedY()); |
1166 | destArea = destArea.removeReversal(); |
1167 | |
1168 | // Now that clipping and flipping is done, rotate certain values that will be used for |
1169 | // UtilsVk::BlitResolveParameters |
1170 | gl::Rectangle sourceAreaOld = sourceArea; |
1171 | gl::Rectangle destAreaOld = destArea; |
1172 | if (srcFramebufferRotation == rotation) |
1173 | { |
1174 | AdjustBlitAreaForPreRotation(framebufferAngle: srcFramebufferRotation, blitAreaIn: sourceAreaOld, |
1175 | framebufferDimensions: srcFramebufferDimensions, blitAreaOut: &sourceArea); |
1176 | AdjustDimensionsAndFlipForPreRotation(framebufferAngle: srcFramebufferRotation, framebufferDimensions: &srcFramebufferDimensions, |
1177 | flipX: &flipX, flipY: &flipY); |
1178 | } |
1179 | SurfaceRotation rememberDestFramebufferRotation = dstFramebufferRotation; |
1180 | if (srcFramebufferRotation == SurfaceRotation::Rotated90Degrees) |
1181 | { |
1182 | dstFramebufferRotation = rotation; |
1183 | } |
1184 | AdjustBlitAreaForPreRotation(framebufferAngle: dstFramebufferRotation, blitAreaIn: destAreaOld, framebufferDimensions: dstFramebufferDimensions, |
1185 | blitAreaOut: &destArea); |
1186 | dstFramebufferRotation = rememberDestFramebufferRotation; |
1187 | |
1188 | // Clip the destination area to the framebuffer size and scissor. Note that we don't care |
1189 | // about the source area anymore. The offset translation is done based on the original source |
1190 | // and destination rectangles. The stretch factor is already calculated as well. |
1191 | gl::Rectangle blitArea; |
1192 | if (!gl::ClipRectangle(source: getRotatedScissoredRenderArea(contextVk), clip: srcClippedDestArea, intersection: &blitArea)) |
1193 | { |
1194 | return angle::Result::Continue; |
1195 | } |
1196 | |
1197 | bool noClip = blitArea == destArea && stretch[0] == 1.0f && stretch[1] == 1.0f; |
1198 | bool noFlip = !flipX && !flipY; |
1199 | bool disableFlippingBlitWithCommand = |
1200 | contextVk->getRenderer()->getFeatures().disableFlippingBlitWithCommand.enabled; |
1201 | |
1202 | UtilsVk::BlitResolveParameters commonParams; |
1203 | commonParams.srcOffset[0] = sourceArea.x; |
1204 | commonParams.srcOffset[1] = sourceArea.y; |
1205 | commonParams.dstOffset[0] = destArea.x; |
1206 | commonParams.dstOffset[1] = destArea.y; |
1207 | commonParams.rotatedOffsetFactor[0] = std::abs(x: sourceArea.width); |
1208 | commonParams.rotatedOffsetFactor[1] = std::abs(x: sourceArea.height); |
1209 | commonParams.stretch[0] = static_cast<float>(stretch[0]); |
1210 | commonParams.stretch[1] = static_cast<float>(stretch[1]); |
1211 | commonParams.srcExtents[0] = srcFramebufferDimensions.width; |
1212 | commonParams.srcExtents[1] = srcFramebufferDimensions.height; |
1213 | commonParams.blitArea = blitArea; |
1214 | commonParams.linear = filter == GL_LINEAR && !isResolve; |
1215 | commonParams.flipX = flipX; |
1216 | commonParams.flipY = flipY; |
1217 | commonParams.rotation = rotation; |
1218 | |
1219 | if (blitColorBuffer) |
1220 | { |
1221 | RenderTargetVk *readRenderTarget = srcFramebufferVk->getColorReadRenderTarget(); |
1222 | UtilsVk::BlitResolveParameters params = commonParams; |
1223 | params.srcLayer = readRenderTarget->getLayerIndex(); |
1224 | |
1225 | // Multisampled images are not allowed to have mips. |
1226 | ASSERT(!isColorResolve || readRenderTarget->getLevelIndex() == gl::LevelIndex(0)); |
1227 | |
1228 | // If there was no clipping and the format capabilities allow us, use Vulkan's builtin blit. |
1229 | // The reason clipping is prohibited in this path is that due to rounding errors, it would |
1230 | // be hard to guarantee the image stretching remains perfect. That also allows us not to |
1231 | // have to transform back the destination clipping to source. |
1232 | // |
1233 | // Non-identity pre-rotation cases do not use Vulkan's builtin blit. |
1234 | // |
1235 | // For simplicity, we either blit all render targets with a Vulkan command, or none. |
1236 | bool canBlitWithCommand = |
1237 | !isColorResolve && noClip && (noFlip || !disableFlippingBlitWithCommand) && |
1238 | HasSrcBlitFeature(renderer, srcRenderTarget: readRenderTarget) && rotation == SurfaceRotation::Identity; |
1239 | // If we need to reinterpret the colorspace then the blit must be done through a shader |
1240 | bool reinterpretsColorspace = |
1241 | mCurrentFramebufferDesc.getWriteControlMode() != gl::SrgbWriteControlMode::Default; |
1242 | bool areChannelsBlitCompatible = true; |
1243 | bool areFormatsIdentical = true; |
1244 | for (size_t colorIndexGL : mState.getEnabledDrawBuffers()) |
1245 | { |
1246 | RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[colorIndexGL]; |
1247 | canBlitWithCommand = |
1248 | canBlitWithCommand && HasDstBlitFeature(renderer, dstRenderTarget: drawRenderTarget); |
1249 | areChannelsBlitCompatible = |
1250 | areChannelsBlitCompatible && |
1251 | AreSrcAndDstColorChannelsBlitCompatible(srcRenderTarget: readRenderTarget, dstRenderTarget: drawRenderTarget); |
1252 | areFormatsIdentical = areFormatsIdentical && |
1253 | AreSrcAndDstFormatsIdentical(srcRenderTarget: readRenderTarget, dstRenderTarget: drawRenderTarget); |
1254 | } |
1255 | |
1256 | // Now that all flipping is done, adjust the offsets for resolve and prerotation |
1257 | if (isColorResolve) |
1258 | { |
1259 | AdjustBlitResolveParametersForResolve(sourceArea, destArea, params: ¶ms); |
1260 | } |
1261 | AdjustBlitResolveParametersForPreRotation(framebufferAngle: rotation, srcFramebufferAngle: srcFramebufferRotation, params: ¶ms); |
1262 | |
1263 | if (canBlitWithCommand && areChannelsBlitCompatible && !reinterpretsColorspace) |
1264 | { |
1265 | for (size_t colorIndexGL : mState.getEnabledDrawBuffers()) |
1266 | { |
1267 | RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[colorIndexGL]; |
1268 | ANGLE_TRY(blitWithCommand(contextVk, sourceArea, destArea, readRenderTarget, |
1269 | drawRenderTarget, filter, true, false, false, flipX, |
1270 | flipY)); |
1271 | } |
1272 | } |
1273 | // If we're not flipping or rotating, use Vulkan's builtin resolve. |
1274 | else if (isColorResolve && !flipX && !flipY && areChannelsBlitCompatible && |
1275 | areFormatsIdentical && rotation == SurfaceRotation::Identity && |
1276 | !reinterpretsColorspace) |
1277 | { |
1278 | // Resolving with a subpass resolve attachment has a few restrictions: |
1279 | // 1.) glBlitFramebuffer() needs to copy the read color attachment to all enabled |
1280 | // attachments in the draw framebuffer, but Vulkan requires a 1:1 relationship for |
1281 | // multisample attachments to resolve attachments in the render pass subpass. |
1282 | // Due to this, we currently only support using resolve attachments when there is a |
1283 | // single draw attachment enabled. |
1284 | // 2.) Using a subpass resolve attachment relies on using the render pass that performs |
1285 | // the draw to still be open, so it can be updated to use the resolve attachment to draw |
1286 | // into. If there's no render pass with commands, then the multisampled render pass is |
1287 | // already done and whose data is already flushed from the tile (in a tile-based |
1288 | // renderer), so there's no chance for the resolve attachment to take advantage of the |
1289 | // data already being present in the tile. |
1290 | |
1291 | // TODO(https://anglebug.com/4968): Support multiple open render passes so we can remove |
1292 | // this hack to 'restore' the finished render pass. |
1293 | // TODO(https://anglebug.com/7553): Look into optimization below in order to remove the |
1294 | // check of whether the current framebuffer is valid. |
1295 | bool isCurrentFramebufferValid = srcFramebufferVk->mCurrentFramebuffer.valid(); |
1296 | |
1297 | // glBlitFramebuffer() needs to copy the read color attachment to all enabled |
1298 | // attachments in the draw framebuffer, but Vulkan requires a 1:1 relationship for |
1299 | // multisample attachments to resolve attachments in the render pass subpass. Due to |
1300 | // this, we currently only support using resolve attachments when there is a single draw |
1301 | // attachment enabled. |
1302 | bool canResolveWithSubpass = isCurrentFramebufferValid && |
1303 | mState.getEnabledDrawBuffers().count() == 1 && |
1304 | mCurrentFramebufferDesc.getLayerCount() == 1 && |
1305 | contextVk->hasStartedRenderPassWithQueueSerial( |
1306 | queueSerial: srcFramebufferVk->getLastRenderPassQueueSerial()); |
1307 | |
1308 | // Additionally, when resolving with a resolve attachment, the src and destination |
1309 | // offsets must match, the render area must match the resolve area, and there should be |
1310 | // no flipping or rotation. Fortunately, in GLES the blit source and destination areas |
1311 | // are already required to be identical. |
1312 | ASSERT(params.srcOffset[0] == params.dstOffset[0] && |
1313 | params.srcOffset[1] == params.dstOffset[1]); |
1314 | canResolveWithSubpass = |
1315 | canResolveWithSubpass && noFlip && rotation == SurfaceRotation::Identity && |
1316 | blitArea == contextVk->getStartedRenderPassCommands().getRenderArea(); |
1317 | |
1318 | if (canResolveWithSubpass) |
1319 | { |
1320 | ANGLE_TRY(resolveColorWithSubpass(contextVk, params)); |
1321 | } |
1322 | else |
1323 | { |
1324 | ANGLE_TRY(resolveColorWithCommand(contextVk, params, |
1325 | &readRenderTarget->getImageForCopy())); |
1326 | } |
1327 | } |
1328 | // Otherwise use a shader to do blit or resolve. |
1329 | else |
1330 | { |
1331 | // Flush the render pass, which may incur a vkQueueSubmit, before taking any views. |
1332 | // Otherwise the view serials would not reflect the render pass they are really used in. |
1333 | // http://crbug.com/1272266#c22 |
1334 | ANGLE_TRY( |
1335 | contextVk->flushCommandsAndEndRenderPass(RenderPassClosureReason::PrepareForBlit)); |
1336 | |
1337 | const vk::ImageView *copyImageView = nullptr; |
1338 | ANGLE_TRY(readRenderTarget->getCopyImageView(contextVk, ©ImageView)); |
1339 | ANGLE_TRY(utilsVk.colorBlitResolve( |
1340 | contextVk, this, &readRenderTarget->getImageForCopy(), copyImageView, params)); |
1341 | } |
1342 | } |
1343 | |
1344 | if (blitDepthBuffer || blitStencilBuffer) |
1345 | { |
1346 | RenderTargetVk *readRenderTarget = srcFramebufferVk->getDepthStencilRenderTarget(); |
1347 | RenderTargetVk *drawRenderTarget = mRenderTargetCache.getDepthStencil(); |
1348 | UtilsVk::BlitResolveParameters params = commonParams; |
1349 | params.srcLayer = readRenderTarget->getLayerIndex(); |
1350 | |
1351 | // Multisampled images are not allowed to have mips. |
1352 | ASSERT(!isDepthStencilResolve || readRenderTarget->getLevelIndex() == gl::LevelIndex(0)); |
1353 | |
1354 | // Similarly, only blit if there's been no clipping or rotating. |
1355 | bool canBlitWithCommand = |
1356 | !isDepthStencilResolve && noClip && (noFlip || !disableFlippingBlitWithCommand) && |
1357 | HasSrcBlitFeature(renderer, srcRenderTarget: readRenderTarget) && |
1358 | HasDstBlitFeature(renderer, dstRenderTarget: drawRenderTarget) && rotation == SurfaceRotation::Identity; |
1359 | bool areChannelsBlitCompatible = |
1360 | AreSrcAndDstDepthStencilChannelsBlitCompatible(srcRenderTarget: readRenderTarget, dstRenderTarget: drawRenderTarget); |
1361 | |
1362 | // glBlitFramebuffer requires that depth/stencil blits have matching formats. |
1363 | ASSERT(AreSrcAndDstFormatsIdentical(readRenderTarget, drawRenderTarget)); |
1364 | |
1365 | if (canBlitWithCommand && areChannelsBlitCompatible) |
1366 | { |
1367 | ANGLE_TRY(blitWithCommand(contextVk, sourceArea, destArea, readRenderTarget, |
1368 | drawRenderTarget, filter, false, blitDepthBuffer, |
1369 | blitStencilBuffer, flipX, flipY)); |
1370 | } |
1371 | else |
1372 | { |
1373 | // Now that all flipping is done, adjust the offsets for resolve and prerotation |
1374 | if (isDepthStencilResolve) |
1375 | { |
1376 | AdjustBlitResolveParametersForResolve(sourceArea, destArea, params: ¶ms); |
1377 | } |
1378 | AdjustBlitResolveParametersForPreRotation(framebufferAngle: rotation, srcFramebufferAngle: srcFramebufferRotation, params: ¶ms); |
1379 | |
1380 | // Create depth- and stencil-only views for reading. |
1381 | vk::DeviceScoped<vk::ImageView> depthView(contextVk->getDevice()); |
1382 | vk::DeviceScoped<vk::ImageView> stencilView(contextVk->getDevice()); |
1383 | |
1384 | vk::ImageHelper *depthStencilImage = &readRenderTarget->getImageForCopy(); |
1385 | vk::LevelIndex levelIndex = |
1386 | depthStencilImage->toVkLevel(levelIndexGL: readRenderTarget->getLevelIndex()); |
1387 | uint32_t layerIndex = readRenderTarget->getLayerIndex(); |
1388 | gl::TextureType textureType = vk::Get2DTextureType(layerCount: depthStencilImage->getLayerCount(), |
1389 | samples: depthStencilImage->getSamples()); |
1390 | |
1391 | if (blitDepthBuffer) |
1392 | { |
1393 | ANGLE_TRY(depthStencilImage->initLayerImageView( |
1394 | contextVk, textureType, VK_IMAGE_ASPECT_DEPTH_BIT, gl::SwizzleState(), |
1395 | &depthView.get(), levelIndex, 1, layerIndex, 1, |
1396 | gl::SrgbWriteControlMode::Default, gl::YuvSamplingMode::Default, |
1397 | vk::ImageHelper::kDefaultImageViewUsageFlags)); |
1398 | } |
1399 | |
1400 | if (blitStencilBuffer) |
1401 | { |
1402 | ANGLE_TRY(depthStencilImage->initLayerImageView( |
1403 | contextVk, textureType, VK_IMAGE_ASPECT_STENCIL_BIT, gl::SwizzleState(), |
1404 | &stencilView.get(), levelIndex, 1, layerIndex, 1, |
1405 | gl::SrgbWriteControlMode::Default, gl::YuvSamplingMode::Default, |
1406 | vk::ImageHelper::kDefaultImageViewUsageFlags)); |
1407 | } |
1408 | |
1409 | // If shader stencil export is not possible, defer stencil blit/resolve to another pass. |
1410 | bool hasShaderStencilExport = |
1411 | contextVk->getRenderer()->getFeatures().supportsShaderStencilExport.enabled; |
1412 | |
1413 | // Blit depth. If shader stencil export is present, blit stencil as well. |
1414 | if (blitDepthBuffer || (blitStencilBuffer && hasShaderStencilExport)) |
1415 | { |
1416 | const vk::ImageView *depth = blitDepthBuffer ? &depthView.get() : nullptr; |
1417 | const vk::ImageView *stencil = |
1418 | blitStencilBuffer && hasShaderStencilExport ? &stencilView.get() : nullptr; |
1419 | |
1420 | ANGLE_TRY(utilsVk.depthStencilBlitResolve(contextVk, this, depthStencilImage, depth, |
1421 | stencil, params)); |
1422 | } |
1423 | |
1424 | // If shader stencil export is not present, blit stencil through a different path. |
1425 | if (blitStencilBuffer && !hasShaderStencilExport) |
1426 | { |
1427 | ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_LOW, |
1428 | "Inefficient BlitFramebuffer operation on the stencil aspect " |
1429 | "due to lack of shader stencil export support"); |
1430 | ANGLE_TRY(utilsVk.stencilBlitResolveNoShaderExport( |
1431 | contextVk, this, depthStencilImage, &stencilView.get(), params)); |
1432 | } |
1433 | |
1434 | vk::ImageView depthViewObject = depthView.release(); |
1435 | vk::ImageView stencilViewObject = stencilView.release(); |
1436 | |
1437 | contextVk->addGarbage(object: &depthViewObject); |
1438 | contextVk->addGarbage(object: &stencilViewObject); |
1439 | } |
1440 | } |
1441 | |
1442 | return angle::Result::Continue; |
1443 | } |
1444 | |
1445 | void FramebufferVk::updateColorResolveAttachment( |
1446 | uint32_t colorIndexGL, |
1447 | vk::ImageOrBufferViewSubresourceSerial resolveImageViewSerial) |
1448 | { |
1449 | mCurrentFramebufferDesc.updateColorResolve(index: colorIndexGL, serial: resolveImageViewSerial); |
1450 | mRenderPassDesc.packColorResolveAttachment(colorIndexGL); |
1451 | } |
1452 | |
1453 | void FramebufferVk::removeColorResolveAttachment(uint32_t colorIndexGL) |
1454 | { |
1455 | mCurrentFramebufferDesc.updateColorResolve(index: colorIndexGL, |
1456 | serial: vk::kInvalidImageOrBufferViewSubresourceSerial); |
1457 | mRenderPassDesc.removeColorResolveAttachment(colorIndexGL); |
1458 | } |
1459 | |
1460 | void FramebufferVk::releaseCurrentFramebuffer(ContextVk *contextVk) |
1461 | { |
1462 | if (mIsCurrentFramebufferCached) |
1463 | { |
1464 | mCurrentFramebuffer.release(); |
1465 | } |
1466 | else |
1467 | { |
1468 | contextVk->addGarbage(object: &mCurrentFramebuffer); |
1469 | } |
1470 | } |
1471 | |
1472 | void FramebufferVk::updateLayerCount() |
1473 | { |
1474 | uint32_t layerCount = std::numeric_limits<uint32_t>::max(); |
1475 | |
1476 | // Color attachments. |
1477 | const auto &colorRenderTargets = mRenderTargetCache.getColors(); |
1478 | for (size_t colorIndexGL : mState.getColorAttachmentsMask()) |
1479 | { |
1480 | RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL]; |
1481 | ASSERT(colorRenderTarget); |
1482 | layerCount = std::min(a: layerCount, b: colorRenderTarget->getLayerCount()); |
1483 | } |
1484 | |
1485 | // Depth/stencil attachment. |
1486 | RenderTargetVk *depthStencilRenderTarget = getDepthStencilRenderTarget(); |
1487 | if (depthStencilRenderTarget) |
1488 | { |
1489 | layerCount = std::min(a: layerCount, b: depthStencilRenderTarget->getLayerCount()); |
1490 | } |
1491 | |
1492 | if (layerCount == std::numeric_limits<uint32_t>::max()) |
1493 | { |
1494 | layerCount = mState.getDefaultLayers(); |
1495 | } |
1496 | |
1497 | // While layer count and view count are mutually exclusive, they result in different render |
1498 | // passes (and thus framebuffers). For multiview, layer count is set to view count and a flag |
1499 | // signifies that the framebuffer is multiview (as opposed to layered). |
1500 | const bool isMultiview = mState.isMultiview(); |
1501 | if (isMultiview) |
1502 | { |
1503 | layerCount = mState.getNumViews(); |
1504 | } |
1505 | |
1506 | mCurrentFramebufferDesc.updateLayerCount(layerCount); |
1507 | mCurrentFramebufferDesc.updateIsMultiview(isMultiview); |
1508 | } |
1509 | |
1510 | angle::Result FramebufferVk::resolveColorWithSubpass(ContextVk *contextVk, |
1511 | const UtilsVk::BlitResolveParameters ¶ms) |
1512 | { |
1513 | // Vulkan requires a 1:1 relationship for multisample attachments to resolve attachments in the |
1514 | // render pass subpass. Due to this, we currently only support using resolve attachments when |
1515 | // there is a single draw attachment enabled. |
1516 | ASSERT(mState.getEnabledDrawBuffers().count() == 1); |
1517 | uint32_t drawColorIndexGL = static_cast<uint32_t>(*mState.getEnabledDrawBuffers().begin()); |
1518 | |
1519 | const gl::State &glState = contextVk->getState(); |
1520 | const gl::Framebuffer *srcFramebuffer = glState.getReadFramebuffer(); |
1521 | FramebufferVk *srcFramebufferVk = vk::GetImpl(glObject: srcFramebuffer); |
1522 | uint32_t readColorIndexGL = srcFramebuffer->getState().getReadIndex(); |
1523 | |
1524 | // Use the draw FBO's color attachments as resolve attachments in the read FBO. |
1525 | // - Assign the draw FBO's color attachment Serial to the read FBO's resolve attachment |
1526 | // - Deactivate the source Framebuffer, since the description changed |
1527 | // - Update the renderpass description to indicate there's a resolve attachment |
1528 | vk::ImageOrBufferViewSubresourceSerial resolveImageViewSerial = |
1529 | mCurrentFramebufferDesc.getColorImageViewSerial(index: drawColorIndexGL); |
1530 | ASSERT(resolveImageViewSerial.viewSerial.valid()); |
1531 | srcFramebufferVk->updateColorResolveAttachment(colorIndexGL: readColorIndexGL, resolveImageViewSerial); |
1532 | srcFramebufferVk->releaseCurrentFramebuffer(contextVk); |
1533 | |
1534 | // Since the source FBO was updated with a resolve attachment it didn't have when the render |
1535 | // pass was started, we need to: |
1536 | // 1. Get the new framebuffer |
1537 | // - The draw framebuffer's ImageView will be used as the resolve attachment, so pass it along |
1538 | // in case vkCreateFramebuffer() needs to be called to create a new vkFramebuffer with the new |
1539 | // resolve attachment. |
1540 | RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[drawColorIndexGL]; |
1541 | const vk::ImageView *resolveImageView = nullptr; |
1542 | ANGLE_TRY(drawRenderTarget->getImageView(contextVk, &resolveImageView)); |
1543 | vk::MaybeImagelessFramebuffer newSrcFramebuffer = {}; |
1544 | ANGLE_TRY(srcFramebufferVk->getFramebuffer(contextVk, &newSrcFramebuffer, drawRenderTarget, |
1545 | resolveImageView, SwapchainResolveMode::Disabled)); |
1546 | // 2. Update the RenderPassCommandBufferHelper with the new framebuffer and render pass |
1547 | vk::RenderPassCommandBufferHelper &commandBufferHelper = |
1548 | contextVk->getStartedRenderPassCommands(); |
1549 | commandBufferHelper.updateRenderPassForResolve(contextVk, newFramebuffer&: newSrcFramebuffer, |
1550 | renderPassDesc: srcFramebufferVk->getRenderPassDesc()); |
1551 | |
1552 | // End the render pass now since we don't (yet) support subpass dependencies. |
1553 | drawRenderTarget->onColorResolve(contextVk, framebufferLayerCount: mCurrentFramebufferDesc.getLayerCount()); |
1554 | ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass( |
1555 | RenderPassClosureReason::AlreadySpecifiedElsewhere)); |
1556 | |
1557 | // Remove the resolve attachment from the source framebuffer. |
1558 | srcFramebufferVk->removeColorResolveAttachment(colorIndexGL: readColorIndexGL); |
1559 | srcFramebufferVk->releaseCurrentFramebuffer(contextVk); |
1560 | |
1561 | return angle::Result::Continue; |
1562 | } |
1563 | |
1564 | angle::Result FramebufferVk::resolveColorWithCommand(ContextVk *contextVk, |
1565 | const UtilsVk::BlitResolveParameters ¶ms, |
1566 | vk::ImageHelper *srcImage) |
1567 | { |
1568 | vk::CommandBufferAccess access; |
1569 | access.onImageTransferRead(aspectFlags: VK_IMAGE_ASPECT_COLOR_BIT, image: srcImage); |
1570 | |
1571 | for (size_t colorIndexGL : mState.getEnabledDrawBuffers()) |
1572 | { |
1573 | RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[colorIndexGL]; |
1574 | vk::ImageHelper &dstImage = drawRenderTarget->getImageForWrite(); |
1575 | |
1576 | access.onImageTransferWrite(levelStart: drawRenderTarget->getLevelIndex(), levelCount: 1, |
1577 | layerStart: drawRenderTarget->getLayerIndex(), layerCount: 1, aspectFlags: VK_IMAGE_ASPECT_COLOR_BIT, |
1578 | image: &dstImage); |
1579 | } |
1580 | |
1581 | vk::OutsideRenderPassCommandBuffer *commandBuffer; |
1582 | ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer)); |
1583 | |
1584 | VkImageResolve resolveRegion = {}; |
1585 | resolveRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
1586 | resolveRegion.srcSubresource.mipLevel = 0; |
1587 | resolveRegion.srcSubresource.baseArrayLayer = params.srcLayer; |
1588 | resolveRegion.srcSubresource.layerCount = 1; |
1589 | resolveRegion.srcOffset.x = params.blitArea.x; |
1590 | resolveRegion.srcOffset.y = params.blitArea.y; |
1591 | resolveRegion.srcOffset.z = 0; |
1592 | resolveRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
1593 | resolveRegion.dstSubresource.layerCount = 1; |
1594 | resolveRegion.dstOffset.x = params.blitArea.x; |
1595 | resolveRegion.dstOffset.y = params.blitArea.y; |
1596 | resolveRegion.dstOffset.z = 0; |
1597 | resolveRegion.extent.width = params.blitArea.width; |
1598 | resolveRegion.extent.height = params.blitArea.height; |
1599 | resolveRegion.extent.depth = 1; |
1600 | |
1601 | angle::VulkanPerfCounters &perfCounters = contextVk->getPerfCounters(); |
1602 | for (size_t colorIndexGL : mState.getEnabledDrawBuffers()) |
1603 | { |
1604 | RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[colorIndexGL]; |
1605 | vk::ImageHelper &dstImage = drawRenderTarget->getImageForWrite(); |
1606 | |
1607 | vk::LevelIndex levelVk = dstImage.toVkLevel(levelIndexGL: drawRenderTarget->getLevelIndex()); |
1608 | resolveRegion.dstSubresource.mipLevel = levelVk.get(); |
1609 | resolveRegion.dstSubresource.baseArrayLayer = drawRenderTarget->getLayerIndex(); |
1610 | |
1611 | srcImage->resolve(dst: &dstImage, region: resolveRegion, commandBuffer); |
1612 | |
1613 | perfCounters.resolveImageCommands++; |
1614 | } |
1615 | |
1616 | return angle::Result::Continue; |
1617 | } |
1618 | |
1619 | gl::FramebufferStatus FramebufferVk::checkStatus(const gl::Context *context) const |
1620 | { |
1621 | // if we have both a depth and stencil buffer, they must refer to the same object |
1622 | // since we only support packed_depth_stencil and not separate depth and stencil |
1623 | if (mState.hasSeparateDepthAndStencilAttachments()) |
1624 | { |
1625 | return gl::FramebufferStatus::Incomplete( |
1626 | GL_FRAMEBUFFER_UNSUPPORTED, |
1627 | reason: gl::err::kFramebufferIncompleteUnsupportedSeparateDepthStencilBuffers); |
1628 | } |
1629 | |
1630 | return gl::FramebufferStatus::Complete(); |
1631 | } |
1632 | |
1633 | angle::Result FramebufferVk::invalidateImpl(ContextVk *contextVk, |
1634 | size_t count, |
1635 | const GLenum *attachments, |
1636 | bool isSubInvalidate, |
1637 | const gl::Rectangle &invalidateArea) |
1638 | { |
1639 | gl::DrawBufferMask invalidateColorBuffers; |
1640 | bool invalidateDepthBuffer = false; |
1641 | bool invalidateStencilBuffer = false; |
1642 | |
1643 | for (size_t i = 0; i < count; ++i) |
1644 | { |
1645 | const GLenum attachment = attachments[i]; |
1646 | |
1647 | switch (attachment) |
1648 | { |
1649 | case GL_DEPTH: |
1650 | case GL_DEPTH_ATTACHMENT: |
1651 | invalidateDepthBuffer = true; |
1652 | break; |
1653 | case GL_STENCIL: |
1654 | case GL_STENCIL_ATTACHMENT: |
1655 | invalidateStencilBuffer = true; |
1656 | break; |
1657 | case GL_DEPTH_STENCIL_ATTACHMENT: |
1658 | invalidateDepthBuffer = true; |
1659 | invalidateStencilBuffer = true; |
1660 | break; |
1661 | default: |
1662 | ASSERT( |
1663 | (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15) || |
1664 | (attachment == GL_COLOR)); |
1665 | |
1666 | invalidateColorBuffers.set( |
1667 | pos: attachment == GL_COLOR ? 0u : (attachment - GL_COLOR_ATTACHMENT0)); |
1668 | } |
1669 | } |
1670 | |
1671 | // Shouldn't try to issue deferred clears if invalidating sub framebuffer. |
1672 | ASSERT(mDeferredClears.empty() || !isSubInvalidate); |
1673 | |
1674 | // Remove deferred clears for the invalidated attachments. |
1675 | if (invalidateDepthBuffer) |
1676 | { |
1677 | mDeferredClears.reset(index: vk::kUnpackedDepthIndex); |
1678 | } |
1679 | if (invalidateStencilBuffer) |
1680 | { |
1681 | mDeferredClears.reset(index: vk::kUnpackedStencilIndex); |
1682 | } |
1683 | for (size_t colorIndexGL : mState.getEnabledDrawBuffers()) |
1684 | { |
1685 | if (invalidateColorBuffers.test(pos: colorIndexGL)) |
1686 | { |
1687 | mDeferredClears.reset(index: colorIndexGL); |
1688 | } |
1689 | } |
1690 | |
1691 | // If there are still deferred clears, redefer them. See relevant comment in invalidateSub. |
1692 | redeferClears(contextVk); |
1693 | |
1694 | const auto &colorRenderTargets = mRenderTargetCache.getColors(); |
1695 | RenderTargetVk *depthStencilRenderTarget = mRenderTargetCache.getDepthStencil(); |
1696 | |
1697 | // If not a partial invalidate, mark the contents of the invalidated attachments as undefined, |
1698 | // so their loadOp can be set to DONT_CARE in the following render pass. |
1699 | if (!isSubInvalidate) |
1700 | { |
1701 | for (size_t colorIndexGL : mState.getEnabledDrawBuffers()) |
1702 | { |
1703 | if (invalidateColorBuffers.test(pos: colorIndexGL)) |
1704 | { |
1705 | RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL]; |
1706 | ASSERT(colorRenderTarget); |
1707 | |
1708 | bool preferToKeepContentsDefined = false; |
1709 | colorRenderTarget->invalidateEntireContent(contextVk, preferToKeepContentsDefinedOut: &preferToKeepContentsDefined); |
1710 | if (preferToKeepContentsDefined) |
1711 | { |
1712 | invalidateColorBuffers.reset(pos: colorIndexGL); |
1713 | } |
1714 | } |
1715 | } |
1716 | |
1717 | // If we have a depth / stencil render target, invalidate its aspects. |
1718 | if (depthStencilRenderTarget) |
1719 | { |
1720 | if (invalidateDepthBuffer) |
1721 | { |
1722 | bool preferToKeepContentsDefined = false; |
1723 | depthStencilRenderTarget->invalidateEntireContent(contextVk, |
1724 | preferToKeepContentsDefinedOut: &preferToKeepContentsDefined); |
1725 | if (preferToKeepContentsDefined) |
1726 | { |
1727 | invalidateDepthBuffer = false; |
1728 | } |
1729 | } |
1730 | if (invalidateStencilBuffer) |
1731 | { |
1732 | bool preferToKeepContentsDefined = false; |
1733 | depthStencilRenderTarget->invalidateEntireStencilContent( |
1734 | contextVk, preferToKeepContentsDefinedOut: &preferToKeepContentsDefined); |
1735 | if (preferToKeepContentsDefined) |
1736 | { |
1737 | invalidateStencilBuffer = false; |
1738 | } |
1739 | } |
1740 | } |
1741 | } |
1742 | |
1743 | // To ensure we invalidate the right renderpass we require that the current framebuffer be the |
1744 | // same as the current renderpass' framebuffer. E.g. prevent sequence like: |
1745 | //- Bind FBO 1, draw |
1746 | //- Bind FBO 2, draw |
1747 | //- Bind FBO 1, invalidate D/S |
1748 | // to invalidate the D/S of FBO 2 since it would be the currently active renderpass. |
1749 | if (contextVk->hasStartedRenderPassWithQueueSerial(queueSerial: mLastRenderPassQueueSerial)) |
1750 | { |
1751 | // Mark the invalidated attachments in the render pass for loadOp and storeOp determination |
1752 | // at its end. |
1753 | vk::PackedAttachmentIndex colorIndexVk(0); |
1754 | for (size_t colorIndexGL : mState.getColorAttachmentsMask()) |
1755 | { |
1756 | if (mState.getEnabledDrawBuffers()[colorIndexGL] && |
1757 | invalidateColorBuffers.test(pos: colorIndexGL)) |
1758 | { |
1759 | contextVk->getStartedRenderPassCommands().invalidateRenderPassColorAttachment( |
1760 | state: contextVk->getState(), colorIndexGL, attachmentIndex: colorIndexVk, invalidateArea); |
1761 | } |
1762 | ++colorIndexVk; |
1763 | } |
1764 | |
1765 | if (depthStencilRenderTarget) |
1766 | { |
1767 | const gl::DepthStencilState &dsState = contextVk->getState().getDepthStencilState(); |
1768 | if (invalidateDepthBuffer) |
1769 | { |
1770 | contextVk->getStartedRenderPassCommands().invalidateRenderPassDepthAttachment( |
1771 | dsState, invalidateArea); |
1772 | } |
1773 | |
1774 | if (invalidateStencilBuffer) |
1775 | { |
1776 | contextVk->getStartedRenderPassCommands().invalidateRenderPassStencilAttachment( |
1777 | dsState, invalidateArea); |
1778 | } |
1779 | } |
1780 | if (invalidateColorBuffers.any()) |
1781 | { |
1782 | // Only end the render pass if invalidating at least one color buffer. Do not end the |
1783 | // render pass if only the depth and/or stencil buffer is invalidated. At least one |
1784 | // application invalidates those every frame, disables depth, and then continues to |
1785 | // draw only to the color buffer. |
1786 | // |
1787 | // Since we are not aware of any application that invalidates a color buffer and |
1788 | // continues to draw to it, we leave that unoptimized. |
1789 | ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass( |
1790 | RenderPassClosureReason::ColorBufferInvalidate)); |
1791 | } |
1792 | } |
1793 | |
1794 | return angle::Result::Continue; |
1795 | } |
1796 | |
1797 | angle::Result FramebufferVk::updateColorAttachment(const gl::Context *context, |
1798 | uint32_t colorIndexGL) |
1799 | { |
1800 | ANGLE_TRY(mRenderTargetCache.updateColorRenderTarget(context, mState, colorIndexGL)); |
1801 | |
1802 | // Update cached masks for masked clears. |
1803 | RenderTargetVk *renderTarget = mRenderTargetCache.getColors()[colorIndexGL]; |
1804 | if (renderTarget) |
1805 | { |
1806 | const angle::Format &actualFormat = renderTarget->getImageActualFormat(); |
1807 | updateActiveColorMasks(colorIndex: colorIndexGL, r: actualFormat.redBits > 0, g: actualFormat.greenBits > 0, |
1808 | b: actualFormat.blueBits > 0, a: actualFormat.alphaBits > 0); |
1809 | |
1810 | const angle::Format &intendedFormat = renderTarget->getImageIntendedFormat(); |
1811 | mEmulatedAlphaAttachmentMask.set( |
1812 | pos: colorIndexGL, value: intendedFormat.alphaBits == 0 && actualFormat.alphaBits > 0); |
1813 | } |
1814 | else |
1815 | { |
1816 | updateActiveColorMasks(colorIndex: colorIndexGL, r: false, g: false, b: false, a: false); |
1817 | } |
1818 | |
1819 | const bool enabledColor = |
1820 | renderTarget && mState.getColorAttachments()[colorIndexGL].isAttached(); |
1821 | const bool enabledResolve = enabledColor && renderTarget->hasResolveAttachment(); |
1822 | |
1823 | if (enabledColor) |
1824 | { |
1825 | mCurrentFramebufferDesc.updateColor(index: colorIndexGL, serial: renderTarget->getDrawSubresourceSerial()); |
1826 | const bool isExternalImage = |
1827 | mState.getColorAttachments()[colorIndexGL].isExternalImageWithoutIndividualSync(); |
1828 | mIsExternalColorAttachments.set(pos: colorIndexGL, value: isExternalImage); |
1829 | mAttachmentHasFrontBufferUsage.set( |
1830 | pos: colorIndexGL, value: mState.getColorAttachments()[colorIndexGL].hasFrontBufferUsage()); |
1831 | } |
1832 | else |
1833 | { |
1834 | mCurrentFramebufferDesc.updateColor(index: colorIndexGL, |
1835 | serial: vk::kInvalidImageOrBufferViewSubresourceSerial); |
1836 | } |
1837 | |
1838 | if (enabledResolve) |
1839 | { |
1840 | mCurrentFramebufferDesc.updateColorResolve(index: colorIndexGL, |
1841 | serial: renderTarget->getResolveSubresourceSerial()); |
1842 | } |
1843 | else |
1844 | { |
1845 | mCurrentFramebufferDesc.updateColorResolve(index: colorIndexGL, |
1846 | serial: vk::kInvalidImageOrBufferViewSubresourceSerial); |
1847 | } |
1848 | |
1849 | return angle::Result::Continue; |
1850 | } |
1851 | |
1852 | angle::Result FramebufferVk::updateDepthStencilAttachment(const gl::Context *context) |
1853 | { |
1854 | ANGLE_TRY(mRenderTargetCache.updateDepthStencilRenderTarget(context, mState)); |
1855 | |
1856 | ContextVk *contextVk = vk::GetImpl(glObject: context); |
1857 | updateDepthStencilAttachmentSerial(contextVk); |
1858 | |
1859 | return angle::Result::Continue; |
1860 | } |
1861 | |
1862 | void FramebufferVk::updateDepthStencilAttachmentSerial(ContextVk *contextVk) |
1863 | { |
1864 | RenderTargetVk *depthStencilRT = getDepthStencilRenderTarget(); |
1865 | |
1866 | if (depthStencilRT != nullptr) |
1867 | { |
1868 | mCurrentFramebufferDesc.updateDepthStencil(serial: depthStencilRT->getDrawSubresourceSerial()); |
1869 | } |
1870 | else |
1871 | { |
1872 | mCurrentFramebufferDesc.updateDepthStencil(serial: vk::kInvalidImageOrBufferViewSubresourceSerial); |
1873 | } |
1874 | |
1875 | if (depthStencilRT != nullptr && depthStencilRT->hasResolveAttachment()) |
1876 | { |
1877 | mCurrentFramebufferDesc.updateDepthStencilResolve( |
1878 | serial: depthStencilRT->getResolveSubresourceSerial()); |
1879 | } |
1880 | else |
1881 | { |
1882 | mCurrentFramebufferDesc.updateDepthStencilResolve( |
1883 | serial: vk::kInvalidImageOrBufferViewSubresourceSerial); |
1884 | } |
1885 | } |
1886 | |
1887 | angle::Result FramebufferVk::flushColorAttachmentUpdates(const gl::Context *context, |
1888 | bool deferClears, |
1889 | uint32_t colorIndexGL) |
1890 | { |
1891 | ContextVk *contextVk = vk::GetImpl(glObject: context); |
1892 | RenderTargetVk *readRenderTarget = nullptr; |
1893 | RenderTargetVk *drawRenderTarget = nullptr; |
1894 | |
1895 | // It's possible for the read and draw color attachments to be different if different surfaces |
1896 | // are bound, so we need to flush any staged updates to both. |
1897 | |
1898 | // Draw |
1899 | drawRenderTarget = mRenderTargetCache.getColorDraw(state: mState, colorIndex: colorIndexGL); |
1900 | if (drawRenderTarget) |
1901 | { |
1902 | if (deferClears) |
1903 | { |
1904 | ANGLE_TRY( |
1905 | drawRenderTarget->flushStagedUpdates(contextVk, &mDeferredClears, colorIndexGL, |
1906 | mCurrentFramebufferDesc.getLayerCount())); |
1907 | } |
1908 | else |
1909 | { |
1910 | ANGLE_TRY(drawRenderTarget->flushStagedUpdates( |
1911 | contextVk, nullptr, 0, mCurrentFramebufferDesc.getLayerCount())); |
1912 | } |
1913 | } |
1914 | |
1915 | // Read |
1916 | if (mState.getReadBufferState() != GL_NONE && mState.getReadIndex() == colorIndexGL) |
1917 | { |
1918 | // Flush staged updates to the read render target as well, but only if it's not the same as |
1919 | // the draw render target. This can happen when the read render target is bound to another |
1920 | // surface. |
1921 | readRenderTarget = mRenderTargetCache.getColorRead(state: mState); |
1922 | if (readRenderTarget && readRenderTarget != drawRenderTarget) |
1923 | { |
1924 | ANGLE_TRY(readRenderTarget->flushStagedUpdates( |
1925 | contextVk, nullptr, 0, mCurrentFramebufferDesc.getLayerCount())); |
1926 | } |
1927 | } |
1928 | |
1929 | return angle::Result::Continue; |
1930 | } |
1931 | |
1932 | angle::Result FramebufferVk::flushDepthStencilAttachmentUpdates(const gl::Context *context, |
1933 | bool deferClears) |
1934 | { |
1935 | ContextVk *contextVk = vk::GetImpl(glObject: context); |
1936 | |
1937 | RenderTargetVk *depthStencilRT = getDepthStencilRenderTarget(); |
1938 | if (depthStencilRT == nullptr) |
1939 | { |
1940 | return angle::Result::Continue; |
1941 | } |
1942 | |
1943 | if (deferClears) |
1944 | { |
1945 | return depthStencilRT->flushStagedUpdates(contextVk, deferredClears: &mDeferredClears, |
1946 | deferredClearIndex: vk::kUnpackedDepthIndex, |
1947 | framebufferLayerCount: mCurrentFramebufferDesc.getLayerCount()); |
1948 | } |
1949 | |
1950 | return depthStencilRT->flushStagedUpdates(contextVk, deferredClears: nullptr, deferredClearIndex: 0, |
1951 | framebufferLayerCount: mCurrentFramebufferDesc.getLayerCount()); |
1952 | } |
1953 | |
1954 | angle::Result FramebufferVk::syncState(const gl::Context *context, |
1955 | GLenum binding, |
1956 | const gl::Framebuffer::DirtyBits &dirtyBits, |
1957 | gl::Command command) |
1958 | { |
1959 | ContextVk *contextVk = vk::GetImpl(glObject: context); |
1960 | |
1961 | vk::FramebufferDesc priorFramebufferDesc = mCurrentFramebufferDesc; |
1962 | |
1963 | // Keep track of which attachments have dirty content and need their staged updates flushed. |
1964 | // The respective functions depend on |mCurrentFramebufferDesc::mLayerCount| which is updated |
1965 | // after all attachment render targets are updated. |
1966 | gl::DrawBufferMask dirtyColorAttachments; |
1967 | bool dirtyDepthStencilAttachment = false; |
1968 | |
1969 | bool shouldUpdateColorMaskAndBlend = false; |
1970 | bool shouldUpdateLayerCount = false; |
1971 | bool shouldUpdateSrgbWriteControlMode = false; |
1972 | |
1973 | // For any updated attachments we'll update their Serials below |
1974 | ASSERT(dirtyBits.any()); |
1975 | for (size_t dirtyBit : dirtyBits) |
1976 | { |
1977 | switch (dirtyBit) |
1978 | { |
1979 | case gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT: |
1980 | case gl::Framebuffer::DIRTY_BIT_DEPTH_BUFFER_CONTENTS: |
1981 | case gl::Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT: |
1982 | case gl::Framebuffer::DIRTY_BIT_STENCIL_BUFFER_CONTENTS: |
1983 | ANGLE_TRY(updateDepthStencilAttachment(context)); |
1984 | shouldUpdateLayerCount = true; |
1985 | dirtyDepthStencilAttachment = true; |
1986 | break; |
1987 | case gl::Framebuffer::DIRTY_BIT_READ_BUFFER: |
1988 | ANGLE_TRY(mRenderTargetCache.update(context, mState, dirtyBits)); |
1989 | break; |
1990 | case gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS: |
1991 | shouldUpdateColorMaskAndBlend = true; |
1992 | shouldUpdateLayerCount = true; |
1993 | break; |
1994 | case gl::Framebuffer::DIRTY_BIT_DEFAULT_WIDTH: |
1995 | case gl::Framebuffer::DIRTY_BIT_DEFAULT_HEIGHT: |
1996 | case gl::Framebuffer::DIRTY_BIT_DEFAULT_SAMPLES: |
1997 | case gl::Framebuffer::DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS: |
1998 | // Invalidate the cache. If we have performance critical code hitting this path we |
1999 | // can add related data (such as width/height) to the cache |
2000 | releaseCurrentFramebuffer(contextVk); |
2001 | break; |
2002 | case gl::Framebuffer::DIRTY_BIT_FRAMEBUFFER_SRGB_WRITE_CONTROL_MODE: |
2003 | shouldUpdateSrgbWriteControlMode = true; |
2004 | break; |
2005 | case gl::Framebuffer::DIRTY_BIT_DEFAULT_LAYERS: |
2006 | shouldUpdateLayerCount = true; |
2007 | break; |
2008 | default: |
2009 | { |
2010 | static_assert(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0, "FB dirty bits"); |
2011 | uint32_t colorIndexGL; |
2012 | if (dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX) |
2013 | { |
2014 | colorIndexGL = static_cast<uint32_t>( |
2015 | dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0); |
2016 | } |
2017 | else |
2018 | { |
2019 | ASSERT(dirtyBit >= gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_0 && |
2020 | dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_MAX); |
2021 | colorIndexGL = static_cast<uint32_t>( |
2022 | dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_0); |
2023 | } |
2024 | |
2025 | ANGLE_TRY(updateColorAttachment(context, colorIndexGL)); |
2026 | |
2027 | // Window system framebuffer only have one color attachment and its property should |
2028 | // never change unless via DIRTY_BIT_DRAW_BUFFERS bit. |
2029 | if (!mState.isDefault()) |
2030 | { |
2031 | shouldUpdateColorMaskAndBlend = true; |
2032 | shouldUpdateLayerCount = true; |
2033 | } |
2034 | dirtyColorAttachments.set(pos: colorIndexGL); |
2035 | |
2036 | break; |
2037 | } |
2038 | } |
2039 | } |
2040 | |
2041 | if (shouldUpdateSrgbWriteControlMode) |
2042 | { |
2043 | // Framebuffer colorspace state has been modified, so refresh the current framebuffer |
2044 | // descriptor to reflect the new state. |
2045 | gl::SrgbWriteControlMode newSrgbWriteControlMode = mState.getWriteControlMode(); |
2046 | mCurrentFramebufferDesc.setWriteControlMode(newSrgbWriteControlMode); |
2047 | mRenderPassDesc.setWriteControlMode(newSrgbWriteControlMode); |
2048 | } |
2049 | |
2050 | if (shouldUpdateColorMaskAndBlend) |
2051 | { |
2052 | contextVk->updateColorMasks(); |
2053 | contextVk->updateBlendFuncsAndEquations(); |
2054 | } |
2055 | |
2056 | if (shouldUpdateLayerCount) |
2057 | { |
2058 | updateLayerCount(); |
2059 | } |
2060 | |
2061 | // Defer clears for draw framebuffer ops. Note that this will result in a render area that |
2062 | // completely covers the framebuffer, even if the operation that follows is scissored. |
2063 | // |
2064 | // Additionally, defer clears for read framebuffer attachments that are not taking part in a |
2065 | // blit operation. |
2066 | const bool isBlitCommand = command >= gl::Command::Blit && command <= gl::Command::BlitAll; |
2067 | |
2068 | bool deferColorClears = binding == GL_DRAW_FRAMEBUFFER; |
2069 | bool deferDepthStencilClears = binding == GL_DRAW_FRAMEBUFFER; |
2070 | if (binding == GL_READ_FRAMEBUFFER && isBlitCommand) |
2071 | { |
2072 | uint32_t blitMask = |
2073 | static_cast<uint32_t>(command) - static_cast<uint32_t>(gl::Command::Blit); |
2074 | if ((blitMask & gl::CommandBlitBufferColor) == 0) |
2075 | { |
2076 | deferColorClears = true; |
2077 | } |
2078 | if ((blitMask & (gl::CommandBlitBufferDepth | gl::CommandBlitBufferStencil)) == 0) |
2079 | { |
2080 | deferDepthStencilClears = true; |
2081 | } |
2082 | } |
2083 | |
2084 | // If we are notified that any attachment is dirty, but we have deferred clears for them, a |
2085 | // flushDeferredClears() call is missing somewhere. ASSERT this to catch these bugs. |
2086 | vk::ClearValuesArray previousDeferredClears = mDeferredClears; |
2087 | |
2088 | for (size_t colorIndexGL : dirtyColorAttachments) |
2089 | { |
2090 | ASSERT(!previousDeferredClears.test(colorIndexGL)); |
2091 | ANGLE_TRY(flushColorAttachmentUpdates(context, deferColorClears, |
2092 | static_cast<uint32_t>(colorIndexGL))); |
2093 | } |
2094 | if (dirtyDepthStencilAttachment) |
2095 | { |
2096 | ASSERT(!previousDeferredClears.testDepth()); |
2097 | ASSERT(!previousDeferredClears.testStencil()); |
2098 | ANGLE_TRY(flushDepthStencilAttachmentUpdates(context, deferDepthStencilClears)); |
2099 | } |
2100 | |
2101 | // No-op redundant changes to prevent closing the RenderPass. |
2102 | if (mCurrentFramebufferDesc == priorFramebufferDesc && |
2103 | mCurrentFramebufferDesc.attachmentCount() > 0) |
2104 | { |
2105 | return angle::Result::Continue; |
2106 | } |
2107 | |
2108 | if (!isBlitCommand) |
2109 | { |
2110 | // Don't end the render pass when handling a blit to resolve, since we may be able to |
2111 | // optimize that path which requires modifying the current render pass. |
2112 | // We're deferring the resolve check to FramebufferVk::blit(), since if the read buffer is |
2113 | // multisampled-render-to-texture, then srcFramebuffer->getSamples(context) gives > 1, but |
2114 | // there's no resolve happening as the read buffer's single sampled image will be used as |
2115 | // blit src. FramebufferVk::blit() will handle those details for us. |
2116 | |
2117 | // ContextVk::onFramebufferChange will end up calling onRenderPassFinished if necessary, |
2118 | // whih will trigger ending of current render pass if needed. But we still need to reset |
2119 | // mLastRenderPassQueueSerial so that it will not get reactivated, since the |
2120 | // mCurrentFramebufferDesc has changed. |
2121 | mLastRenderPassQueueSerial = QueueSerial(); |
2122 | } |
2123 | |
2124 | updateRenderPassDesc(contextVk); |
2125 | |
2126 | // Deactivate Framebuffer |
2127 | releaseCurrentFramebuffer(contextVk); |
2128 | |
2129 | // Notify the ContextVk to update the pipeline desc. |
2130 | return contextVk->onFramebufferChange(framebufferVk: this, command); |
2131 | } |
2132 | |
2133 | void FramebufferVk::updateRenderPassDesc(ContextVk *contextVk) |
2134 | { |
2135 | mRenderPassDesc = {}; |
2136 | mRenderPassDesc.setSamples(getSamples()); |
2137 | mRenderPassDesc.setViewCount( |
2138 | mState.isMultiview() && mState.getNumViews() > 1 ? mState.getNumViews() : 0); |
2139 | |
2140 | // Color attachments. |
2141 | const auto &colorRenderTargets = mRenderTargetCache.getColors(); |
2142 | const gl::DrawBufferMask colorAttachmentMask = mState.getColorAttachmentsMask(); |
2143 | for (size_t colorIndexGL = 0; colorIndexGL < colorAttachmentMask.size(); ++colorIndexGL) |
2144 | { |
2145 | if (colorAttachmentMask[colorIndexGL]) |
2146 | { |
2147 | RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL]; |
2148 | ASSERT(colorRenderTarget); |
2149 | mRenderPassDesc.packColorAttachment( |
2150 | colorIndexGL, formatID: colorRenderTarget->getImageForRenderPass().getActualFormatID()); |
2151 | |
2152 | // Add the resolve attachment, if any. |
2153 | if (colorRenderTarget->hasResolveAttachment()) |
2154 | { |
2155 | mRenderPassDesc.packColorResolveAttachment(colorIndexGL); |
2156 | } |
2157 | } |
2158 | else |
2159 | { |
2160 | mRenderPassDesc.packColorAttachmentGap(colorIndexGL); |
2161 | } |
2162 | } |
2163 | |
2164 | // Depth/stencil attachment. |
2165 | RenderTargetVk *depthStencilRenderTarget = getDepthStencilRenderTarget(); |
2166 | if (depthStencilRenderTarget) |
2167 | { |
2168 | mRenderPassDesc.packDepthStencilAttachment( |
2169 | angleFormatID: depthStencilRenderTarget->getImageForRenderPass().getActualFormatID()); |
2170 | |
2171 | // Add the resolve attachment, if any. |
2172 | if (depthStencilRenderTarget->hasResolveAttachment()) |
2173 | { |
2174 | mRenderPassDesc.packDepthStencilResolveAttachment(); |
2175 | } |
2176 | } |
2177 | |
2178 | if (contextVk->isInFramebufferFetchMode()) |
2179 | { |
2180 | mRenderPassDesc.setFramebufferFetchMode(true); |
2181 | } |
2182 | |
2183 | if (contextVk->getFeatures().enableMultisampledRenderToTexture.enabled) |
2184 | { |
2185 | // Update descriptions regarding multisampled-render-to-texture use. |
2186 | bool isRenderToTexture = false; |
2187 | for (size_t colorIndexGL : mState.getEnabledDrawBuffers()) |
2188 | { |
2189 | const gl::FramebufferAttachment *color = mState.getColorAttachment(colorAttachment: colorIndexGL); |
2190 | ASSERT(color); |
2191 | |
2192 | if (color->isRenderToTexture()) |
2193 | { |
2194 | isRenderToTexture = true; |
2195 | break; |
2196 | } |
2197 | } |
2198 | const gl::FramebufferAttachment *depthStencil = mState.getDepthStencilAttachment(); |
2199 | if (depthStencil && depthStencil->isRenderToTexture()) |
2200 | { |
2201 | isRenderToTexture = true; |
2202 | } |
2203 | |
2204 | mCurrentFramebufferDesc.updateRenderToTexture(isRenderToTexture); |
2205 | mRenderPassDesc.updateRenderToTexture(isRenderToTexture); |
2206 | } |
2207 | |
2208 | mCurrentFramebufferDesc.updateUnresolveMask(unresolveMask: {}); |
2209 | mRenderPassDesc.setWriteControlMode(mCurrentFramebufferDesc.getWriteControlMode()); |
2210 | |
2211 | updateLegacyDither(contextVk); |
2212 | } |
2213 | |
2214 | angle::Result FramebufferVk::getAttachmentsAndRenderTargets( |
2215 | ContextVk *contextVk, |
2216 | const vk::ImageView *resolveImageViewIn, |
2217 | RenderTargetVk *resolveRenderTargetIn, |
2218 | vk::FramebufferAttachmentsVector<VkImageView> *attachments, |
2219 | vk::FramebufferAttachmentsVector<RenderTargetInfo> *renderTargetsInfoOut) |
2220 | { |
2221 | // Color attachments. |
2222 | const auto &colorRenderTargets = mRenderTargetCache.getColors(); |
2223 | for (size_t colorIndexGL : mState.getColorAttachmentsMask()) |
2224 | { |
2225 | RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL]; |
2226 | ASSERT(colorRenderTarget); |
2227 | |
2228 | const vk::ImageView *imageView = nullptr; |
2229 | ANGLE_TRY(colorRenderTarget->getImageViewWithColorspace( |
2230 | contextVk, mCurrentFramebufferDesc.getWriteControlMode(), &imageView)); |
2231 | |
2232 | attachments->push_back(value: imageView->getHandle()); |
2233 | renderTargetsInfoOut->emplace_back( |
2234 | args: RenderTargetInfo(colorRenderTarget, RenderTargetImage::AttachmentImage)); |
2235 | } |
2236 | |
2237 | // Depth/stencil attachment. |
2238 | RenderTargetVk *depthStencilRenderTarget = getDepthStencilRenderTarget(); |
2239 | if (depthStencilRenderTarget) |
2240 | { |
2241 | const vk::ImageView *imageView = nullptr; |
2242 | ANGLE_TRY(depthStencilRenderTarget->getImageView(contextVk, &imageView)); |
2243 | |
2244 | attachments->push_back(value: imageView->getHandle()); |
2245 | renderTargetsInfoOut->emplace_back( |
2246 | args: RenderTargetInfo(depthStencilRenderTarget, RenderTargetImage::AttachmentImage)); |
2247 | } |
2248 | |
2249 | // Color resolve attachments. |
2250 | if (resolveImageViewIn) |
2251 | { |
2252 | ASSERT(!HasResolveAttachment(colorRenderTargets, mState.getEnabledDrawBuffers())); |
2253 | ASSERT(resolveRenderTargetIn); |
2254 | |
2255 | // Need to use the passed in ImageView for the resolve attachment, since it came from |
2256 | // another Framebuffer. |
2257 | attachments->push_back(value: resolveImageViewIn->getHandle()); |
2258 | renderTargetsInfoOut->emplace_back( |
2259 | args: RenderTargetInfo(resolveRenderTargetIn, (resolveRenderTargetIn->hasResolveAttachment()) |
2260 | ? RenderTargetImage::ResolveImage |
2261 | : RenderTargetImage::AttachmentImage)); |
2262 | } |
2263 | else |
2264 | { |
2265 | // This Framebuffer owns all of the ImageViews, including its own resolve ImageViews. |
2266 | for (size_t colorIndexGL : mState.getColorAttachmentsMask()) |
2267 | { |
2268 | RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL]; |
2269 | ASSERT(colorRenderTarget); |
2270 | |
2271 | if (colorRenderTarget->hasResolveAttachment()) |
2272 | { |
2273 | const vk::ImageView *resolveImageView = nullptr; |
2274 | ANGLE_TRY(colorRenderTarget->getResolveImageView(contextVk, &resolveImageView)); |
2275 | |
2276 | attachments->push_back(value: resolveImageView->getHandle()); |
2277 | renderTargetsInfoOut->emplace_back( |
2278 | args: RenderTargetInfo(colorRenderTarget, RenderTargetImage::ResolveImage)); |
2279 | } |
2280 | } |
2281 | } |
2282 | |
2283 | // Depth/stencil resolve attachment. |
2284 | if (depthStencilRenderTarget && depthStencilRenderTarget->hasResolveAttachment()) |
2285 | { |
2286 | const vk::ImageView *imageView = nullptr; |
2287 | ANGLE_TRY(depthStencilRenderTarget->getResolveImageView(contextVk, &imageView)); |
2288 | |
2289 | attachments->push_back(value: imageView->getHandle()); |
2290 | renderTargetsInfoOut->emplace_back( |
2291 | args: RenderTargetInfo(depthStencilRenderTarget, RenderTargetImage::ResolveImage)); |
2292 | } |
2293 | |
2294 | return angle::Result::Continue; |
2295 | } |
2296 | |
2297 | angle::Result FramebufferVk::getFramebuffer(ContextVk *contextVk, |
2298 | vk::MaybeImagelessFramebuffer *framebufferOut, |
2299 | RenderTargetVk *resolveRenderTargetIn, |
2300 | const vk::ImageView *resolveImageViewIn, |
2301 | const SwapchainResolveMode swapchainResolveMode) |
2302 | { |
2303 | ASSERT(mCurrentFramebufferDesc.hasFramebufferFetch() == mRenderPassDesc.hasFramebufferFetch()); |
2304 | |
2305 | // When using imageless framebuffers, the framebuffer cache is not utilized. |
2306 | bool useImagelessFramebuffer = |
2307 | contextVk->getFeatures().supportsImagelessFramebuffer.enabled && mBackbuffer == nullptr; |
2308 | vk::ImagelessStatus useImagelessFramebufferStatus = (useImagelessFramebuffer) |
2309 | ? vk::ImagelessStatus::Imageless |
2310 | : vk::ImagelessStatus::NotImageless; |
2311 | |
2312 | // First return a presently valid Framebuffer |
2313 | if (mCurrentFramebuffer.valid()) |
2314 | { |
2315 | // With imageless framebuffers, the image views used for the beginning of the render pass |
2316 | // should be updated. |
2317 | if (useImagelessFramebuffer) |
2318 | { |
2319 | vk::FramebufferAttachmentsVector<VkImageView> attachments; |
2320 | vk::FramebufferAttachmentsVector<RenderTargetInfo> renderTargetsInfo; |
2321 | ANGLE_TRY(getAttachmentsAndRenderTargets(contextVk, resolveImageViewIn, |
2322 | resolveRenderTargetIn, &attachments, |
2323 | &renderTargetsInfo)); |
2324 | framebufferOut->updateFramebuffer(newFramebufferHandle: mCurrentFramebuffer.getHandle(), newImageViews: &attachments, |
2325 | imagelessStatus: useImagelessFramebufferStatus); |
2326 | } |
2327 | |
2328 | framebufferOut->setHandle(mCurrentFramebuffer.getHandle()); |
2329 | return angle::Result::Continue; |
2330 | } |
2331 | |
2332 | // No current FB, so now check for previously cached Framebuffer. |
2333 | if (mBackbuffer == nullptr && !useImagelessFramebuffer && |
2334 | contextVk->getShareGroup()->getFramebufferCache().get(contextVk, desc: mCurrentFramebufferDesc, |
2335 | framebuffer&: mCurrentFramebuffer)) |
2336 | { |
2337 | ASSERT(mCurrentFramebuffer.valid()); |
2338 | mIsCurrentFramebufferCached = true; |
2339 | framebufferOut->setHandle(mCurrentFramebuffer.getHandle()); |
2340 | return angle::Result::Continue; |
2341 | } |
2342 | |
2343 | const vk::RenderPass *compatibleRenderPass = nullptr; |
2344 | ANGLE_TRY(contextVk->getCompatibleRenderPass(mRenderPassDesc, &compatibleRenderPass)); |
2345 | |
2346 | // If we've a Framebuffer provided by a Surface (default FBO/backbuffer), query it. |
2347 | if (mBackbuffer) |
2348 | { |
2349 | return mBackbuffer->getCurrentFramebuffer( |
2350 | context: contextVk, |
2351 | fetchMode: mRenderPassDesc.hasFramebufferFetch() ? FramebufferFetchMode::Enabled |
2352 | : FramebufferFetchMode::Disabled, |
2353 | compatibleRenderPass: *compatibleRenderPass, swapchainResolveMode, framebufferOut); |
2354 | } |
2355 | |
2356 | // Gather VkImageViews over all FBO attachments, also size of attached region. |
2357 | vk::FramebufferAttachmentsVector<VkImageView> attachments; |
2358 | vk::FramebufferAttachmentsVector<RenderTargetInfo> renderTargetsInfo; |
2359 | gl::Extents attachmentsSize = mState.getExtents(); |
2360 | ASSERT(attachmentsSize.width != 0 && attachmentsSize.height != 0); |
2361 | ANGLE_TRY(getAttachmentsAndRenderTargets(contextVk, resolveImageViewIn, resolveRenderTargetIn, |
2362 | &attachments, &renderTargetsInfo)); |
2363 | |
2364 | // Create new framebuffer. |
2365 | vk::FramebufferHelper newFramebuffer; |
2366 | |
2367 | VkFramebufferCreateInfo framebufferInfo = {}; |
2368 | framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; |
2369 | framebufferInfo.flags = 0; |
2370 | framebufferInfo.renderPass = compatibleRenderPass->getHandle(); |
2371 | framebufferInfo.attachmentCount = static_cast<uint32_t>(attachments.size()); |
2372 | framebufferInfo.pAttachments = attachments.data(); |
2373 | framebufferInfo.width = static_cast<uint32_t>(attachmentsSize.width); |
2374 | framebufferInfo.height = static_cast<uint32_t>(attachmentsSize.height); |
2375 | framebufferInfo.layers = (!mCurrentFramebufferDesc.isMultiview()) |
2376 | ? std::max(a: mCurrentFramebufferDesc.getLayerCount(), b: 1u) |
2377 | : 1; |
2378 | |
2379 | // Check that our description matches our attachments. Can catch implementation bugs. |
2380 | ASSERT(static_cast<uint32_t>(attachments.size()) == mCurrentFramebufferDesc.attachmentCount()); |
2381 | |
2382 | if (!useImagelessFramebuffer) |
2383 | { |
2384 | // Since the cache key FramebufferDesc can't distinguish between |
2385 | // two FramebufferHelper, if they both have 0 attachment, but their sizes |
2386 | // are different, we could have wrong cache hit(new framebufferHelper has |
2387 | // a bigger height and width, but get cache hit with framebufferHelper of |
2388 | // lower height and width). As a workaround, do not cache the |
2389 | // FramebufferHelper if it doesn't have any attachment. |
2390 | ANGLE_TRY(newFramebuffer.init(contextVk, framebufferInfo)); |
2391 | if (!attachments.empty()) |
2392 | { |
2393 | insertCache(contextVk, desc: mCurrentFramebufferDesc, newFramebuffer: std::move(newFramebuffer)); |
2394 | |
2395 | bool result = contextVk->getShareGroup()->getFramebufferCache().get( |
2396 | contextVk, desc: mCurrentFramebufferDesc, framebuffer&: mCurrentFramebuffer); |
2397 | ASSERT(result); |
2398 | mIsCurrentFramebufferCached = true; |
2399 | } |
2400 | else |
2401 | { |
2402 | mCurrentFramebuffer = std::move(newFramebuffer.getFramebuffer()); |
2403 | mIsCurrentFramebufferCached = false; |
2404 | } |
2405 | } |
2406 | else |
2407 | { |
2408 | // For imageless framebuffers, attachment image and create info objects should be defined |
2409 | // when creating the new framebuffer. |
2410 | std::vector<VkFramebufferAttachmentImageInfoKHR> fbAttachmentImageInfoArray; |
2411 | |
2412 | for (auto const &info : renderTargetsInfo) |
2413 | { |
2414 | vk::ImageHelper *renderTargetImage = |
2415 | (info.renderTargetImage == RenderTargetImage::ResolveImage) |
2416 | ? &info.renderTarget->getResolveImageForRenderPass() |
2417 | : &info.renderTarget->getImageForRenderPass(); |
2418 | uint32_t renderTargetLevel = info.renderTarget->getLevelIndex().get(); |
2419 | uint32_t renderTargetLayerCount = info.renderTarget->getLayerCount(); |
2420 | |
2421 | VkFramebufferAttachmentImageInfoKHR fbAttachmentImageInfo = {}; |
2422 | fbAttachmentImageInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO_KHR; |
2423 | |
2424 | uint32_t baseLevel = |
2425 | static_cast<uint32_t>(renderTargetImage->getFirstAllocatedLevel().get()); |
2426 | uint32_t level = (renderTargetLevel > baseLevel) ? (renderTargetLevel - baseLevel) : 0; |
2427 | uint32_t fbAttachmentWidth = renderTargetImage->getExtents().width >> level; |
2428 | uint32_t fbAttachmentHeight = renderTargetImage->getExtents().height >> level; |
2429 | fbAttachmentImageInfo.width = (fbAttachmentWidth > 0) ? fbAttachmentWidth : 1; |
2430 | fbAttachmentImageInfo.height = (fbAttachmentHeight > 0) ? fbAttachmentHeight : 1; |
2431 | |
2432 | fbAttachmentImageInfo.layerCount = |
2433 | (mCurrentFramebufferDesc.isMultiview()) |
2434 | ? std::max(a: static_cast<uint32_t>(mRenderPassDesc.viewCount()), b: 1u) |
2435 | : renderTargetLayerCount; |
2436 | fbAttachmentImageInfo.flags = renderTargetImage->getCreateFlags(); |
2437 | fbAttachmentImageInfo.usage = renderTargetImage->getUsage(); |
2438 | fbAttachmentImageInfo.viewFormatCount = |
2439 | static_cast<uint32_t>(renderTargetImage->getViewFormats().max_size()); |
2440 | fbAttachmentImageInfo.pViewFormats = renderTargetImage->getViewFormats().data(); |
2441 | |
2442 | fbAttachmentImageInfoArray.push_back(x: fbAttachmentImageInfo); |
2443 | } |
2444 | |
2445 | VkFramebufferAttachmentsCreateInfoKHR fbAttachmentsCreateInfo = {}; |
2446 | fbAttachmentsCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO_KHR; |
2447 | fbAttachmentsCreateInfo.attachmentImageInfoCount = |
2448 | static_cast<uint32_t>(fbAttachmentImageInfoArray.size()); |
2449 | fbAttachmentsCreateInfo.pAttachmentImageInfos = fbAttachmentImageInfoArray.data(); |
2450 | |
2451 | framebufferInfo.flags |= VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR; |
2452 | framebufferInfo.pAttachments = nullptr; |
2453 | vk::AddToPNextChain(chainStart: &framebufferInfo, ptr: &fbAttachmentsCreateInfo); |
2454 | |
2455 | ANGLE_TRY(newFramebuffer.init(contextVk, framebufferInfo)); |
2456 | mCurrentFramebuffer.setHandle(newFramebuffer.getFramebuffer().release()); |
2457 | |
2458 | // Update the image views to be used to begin the render pass. |
2459 | framebufferOut->updateFramebuffer(newFramebufferHandle: mCurrentFramebuffer.getHandle(), newImageViews: &attachments, |
2460 | imagelessStatus: useImagelessFramebufferStatus); |
2461 | } |
2462 | |
2463 | ASSERT(mCurrentFramebuffer.valid()); |
2464 | |
2465 | framebufferOut->setHandle(mCurrentFramebuffer.getHandle()); |
2466 | return angle::Result::Continue; |
2467 | } |
2468 | |
2469 | void FramebufferVk::mergeClearsWithDeferredClears( |
2470 | gl::DrawBufferMask clearColorBuffers, |
2471 | bool clearDepth, |
2472 | bool clearStencil, |
2473 | const VkClearColorValue &clearColorValue, |
2474 | const VkClearDepthStencilValue &clearDepthStencilValue) |
2475 | { |
2476 | // Apply clears to mDeferredClears. Note that clears override deferred clears. |
2477 | |
2478 | // Color clears. |
2479 | for (size_t colorIndexGL : clearColorBuffers) |
2480 | { |
2481 | ASSERT(mState.getEnabledDrawBuffers().test(colorIndexGL)); |
2482 | VkClearValue clearValue = getCorrectedColorClearValue(colorIndexGL, clearColor: clearColorValue); |
2483 | mDeferredClears.store(index: static_cast<uint32_t>(colorIndexGL), aspectFlags: VK_IMAGE_ASPECT_COLOR_BIT, |
2484 | clearValue); |
2485 | } |
2486 | |
2487 | // Depth and stencil clears. |
2488 | VkImageAspectFlags dsAspectFlags = 0; |
2489 | VkClearValue dsClearValue = {}; |
2490 | dsClearValue.depthStencil = clearDepthStencilValue; |
2491 | if (clearDepth) |
2492 | { |
2493 | dsAspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT; |
2494 | } |
2495 | if (clearStencil) |
2496 | { |
2497 | dsAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; |
2498 | } |
2499 | |
2500 | if (dsAspectFlags != 0) |
2501 | { |
2502 | mDeferredClears.store(index: vk::kUnpackedDepthIndex, aspectFlags: dsAspectFlags, clearValue: dsClearValue); |
2503 | } |
2504 | } |
2505 | |
2506 | angle::Result FramebufferVk::clearWithDraw(ContextVk *contextVk, |
2507 | const gl::Rectangle &clearArea, |
2508 | gl::DrawBufferMask clearColorBuffers, |
2509 | bool clearDepth, |
2510 | bool clearStencil, |
2511 | gl::BlendStateExt::ColorMaskStorage::Type colorMasks, |
2512 | uint8_t stencilMask, |
2513 | const VkClearColorValue &clearColorValue, |
2514 | const VkClearDepthStencilValue &clearDepthStencilValue) |
2515 | { |
2516 | // All deferred clears should be handled already. |
2517 | ASSERT(mDeferredClears.empty()); |
2518 | |
2519 | UtilsVk::ClearFramebufferParameters params = {}; |
2520 | params.clearArea = clearArea; |
2521 | params.colorClearValue = clearColorValue; |
2522 | params.depthStencilClearValue = clearDepthStencilValue; |
2523 | params.stencilMask = stencilMask; |
2524 | |
2525 | params.clearColor = true; |
2526 | params.clearDepth = clearDepth; |
2527 | params.clearStencil = clearStencil; |
2528 | |
2529 | const auto &colorRenderTargets = mRenderTargetCache.getColors(); |
2530 | for (size_t colorIndexGL : clearColorBuffers) |
2531 | { |
2532 | const RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL]; |
2533 | ASSERT(colorRenderTarget); |
2534 | |
2535 | params.colorFormat = &colorRenderTarget->getImageForRenderPass().getActualFormat(); |
2536 | params.colorAttachmentIndexGL = static_cast<uint32_t>(colorIndexGL); |
2537 | params.colorMaskFlags = |
2538 | gl::BlendStateExt::ColorMaskStorage::GetValueIndexed(index: colorIndexGL, values: colorMasks); |
2539 | if (mEmulatedAlphaAttachmentMask[colorIndexGL]) |
2540 | { |
2541 | params.colorMaskFlags &= ~VK_COLOR_COMPONENT_A_BIT; |
2542 | } |
2543 | |
2544 | // TODO: implement clear of layered framebuffers. UtilsVk::clearFramebuffer should add a |
2545 | // geometry shader that is instanced layerCount times (or loops layerCount times), each time |
2546 | // selecting a different layer. |
2547 | // http://anglebug.com/5453 |
2548 | ASSERT(mCurrentFramebufferDesc.isMultiview() || colorRenderTarget->getLayerCount() == 1); |
2549 | |
2550 | ANGLE_TRY(contextVk->getUtils().clearFramebuffer(contextVk, this, params)); |
2551 | |
2552 | // Clear depth/stencil only once! |
2553 | params.clearDepth = false; |
2554 | params.clearStencil = false; |
2555 | } |
2556 | |
2557 | // If there was no color clear, clear depth/stencil alone. |
2558 | if (params.clearDepth || params.clearStencil) |
2559 | { |
2560 | params.clearColor = false; |
2561 | ANGLE_TRY(contextVk->getUtils().clearFramebuffer(contextVk, this, params)); |
2562 | } |
2563 | |
2564 | return angle::Result::Continue; |
2565 | } |
2566 | |
2567 | VkClearValue FramebufferVk::getCorrectedColorClearValue(size_t colorIndexGL, |
2568 | const VkClearColorValue &clearColor) const |
2569 | { |
2570 | VkClearValue clearValue = {}; |
2571 | clearValue.color = clearColor; |
2572 | |
2573 | if (!mEmulatedAlphaAttachmentMask[colorIndexGL]) |
2574 | { |
2575 | return clearValue; |
2576 | } |
2577 | |
2578 | // If the render target doesn't have alpha, but its emulated format has it, clear the alpha |
2579 | // to 1. |
2580 | RenderTargetVk *renderTarget = getColorDrawRenderTarget(colorIndexGL); |
2581 | const angle::Format &format = renderTarget->getImageActualFormat(); |
2582 | |
2583 | if (format.isUint()) |
2584 | { |
2585 | clearValue.color.uint32[3] = kEmulatedAlphaValue; |
2586 | } |
2587 | else if (format.isSint()) |
2588 | { |
2589 | clearValue.color.int32[3] = kEmulatedAlphaValue; |
2590 | } |
2591 | else |
2592 | { |
2593 | clearValue.color.float32[3] = kEmulatedAlphaValue; |
2594 | } |
2595 | |
2596 | return clearValue; |
2597 | } |
2598 | |
2599 | void FramebufferVk::redeferClears(ContextVk *contextVk) |
2600 | { |
2601 | // Called when redeferring clears of the draw framebuffer. In that case, there can't be any |
2602 | // render passes open, otherwise the clear would have applied to the render pass. In the |
2603 | // exceptional occasion in blit where the read framebuffer accumulates deferred clears, it can |
2604 | // be deferred while this assumption doesn't hold (and redeferClearsForReadFramebuffer should be |
2605 | // used instead). |
2606 | ASSERT(!contextVk->hasActiveRenderPass() || !mDeferredClears.any()); |
2607 | redeferClearsImpl(contextVk); |
2608 | } |
2609 | |
2610 | void FramebufferVk::redeferClearsForReadFramebuffer(ContextVk *contextVk) |
2611 | { |
2612 | redeferClearsImpl(contextVk); |
2613 | } |
2614 | |
2615 | void FramebufferVk::redeferClearsImpl(ContextVk *contextVk) |
2616 | { |
2617 | // Set the appropriate aspect and clear values for depth and stencil. |
2618 | VkImageAspectFlags dsAspectFlags = 0; |
2619 | VkClearValue dsClearValue = {}; |
2620 | dsClearValue.depthStencil.depth = mDeferredClears.getDepthValue(); |
2621 | dsClearValue.depthStencil.stencil = mDeferredClears.getStencilValue(); |
2622 | |
2623 | if (mDeferredClears.testDepth()) |
2624 | { |
2625 | dsAspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT; |
2626 | mDeferredClears.reset(index: vk::kUnpackedDepthIndex); |
2627 | } |
2628 | |
2629 | if (mDeferredClears.testStencil()) |
2630 | { |
2631 | dsAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; |
2632 | mDeferredClears.reset(index: vk::kUnpackedStencilIndex); |
2633 | } |
2634 | |
2635 | // Go through deferred clears and stage the clears for future. |
2636 | for (size_t colorIndexGL : mDeferredClears.getColorMask()) |
2637 | { |
2638 | RenderTargetVk *renderTarget = getColorDrawRenderTarget(colorIndexGL); |
2639 | gl::ImageIndex imageIndex = |
2640 | renderTarget->getImageIndexForClear(layerCount: mCurrentFramebufferDesc.getLayerCount()); |
2641 | renderTarget->getImageForWrite().stageClear(index: imageIndex, aspectFlags: VK_IMAGE_ASPECT_COLOR_BIT, |
2642 | clearValue: mDeferredClears[colorIndexGL]); |
2643 | mDeferredClears.reset(index: colorIndexGL); |
2644 | } |
2645 | |
2646 | if (dsAspectFlags) |
2647 | { |
2648 | RenderTargetVk *renderTarget = getDepthStencilRenderTarget(); |
2649 | ASSERT(renderTarget); |
2650 | |
2651 | gl::ImageIndex imageIndex = |
2652 | renderTarget->getImageIndexForClear(layerCount: mCurrentFramebufferDesc.getLayerCount()); |
2653 | renderTarget->getImageForWrite().stageClear(index: imageIndex, aspectFlags: dsAspectFlags, clearValue: dsClearValue); |
2654 | } |
2655 | } |
2656 | |
2657 | void FramebufferVk::clearWithCommand(ContextVk *contextVk, |
2658 | const gl::Rectangle &scissoredRenderArea, |
2659 | ClearWithCommand behavior, |
2660 | vk::ClearValuesArray *clears) |
2661 | { |
2662 | // Clear is not affected by viewport, so ContextVk::updateScissor may have decided on a smaller |
2663 | // render area. Grow the render area to the full framebuffer size as this clear path is taken |
2664 | // when not scissored. |
2665 | vk::RenderPassCommandBufferHelper *renderPassCommands = |
2666 | &contextVk->getStartedRenderPassCommands(); |
2667 | renderPassCommands->growRenderArea(contextVk, newRenderArea: scissoredRenderArea); |
2668 | |
2669 | gl::AttachmentVector<VkClearAttachment> attachments; |
2670 | |
2671 | const bool optimizeWithLoadOp = behavior == ClearWithCommand::OptimizeWithLoadOp; |
2672 | |
2673 | // Go through deferred clears and add them to the list of attachments to clear. If any |
2674 | // attachment is unused, skip the clear. clearWithLoadOp will follow and move the remaining |
2675 | // clears up to loadOp. |
2676 | vk::PackedAttachmentIndex colorIndexVk(0); |
2677 | for (size_t colorIndexGL : mState.getColorAttachmentsMask()) |
2678 | { |
2679 | if (clears->getColorMask().test(pos: colorIndexGL)) |
2680 | { |
2681 | if (!renderPassCommands->hasAnyColorAccess(packedAttachmentIndex: colorIndexVk) && optimizeWithLoadOp) |
2682 | { |
2683 | // Skip this attachment, so we can use a renderpass loadOp to clear it instead. |
2684 | // Note that if loadOp=Clear was already used for this color attachment, it will be |
2685 | // overriden by the new clear, which is valid because the attachment wasn't used in |
2686 | // between. |
2687 | ++colorIndexVk; |
2688 | continue; |
2689 | } |
2690 | |
2691 | attachments.emplace_back(args: VkClearAttachment{.aspectMask: VK_IMAGE_ASPECT_COLOR_BIT, |
2692 | .colorAttachment: static_cast<uint32_t>(colorIndexGL), |
2693 | .clearValue: (*clears)[colorIndexGL]}); |
2694 | clears->reset(index: colorIndexGL); |
2695 | ++contextVk->getPerfCounters().colorClearAttachments; |
2696 | |
2697 | renderPassCommands->onColorAccess(packedAttachmentIndex: colorIndexVk, access: vk::ResourceAccess::ReadWrite); |
2698 | } |
2699 | ++colorIndexVk; |
2700 | } |
2701 | |
2702 | // Add depth and stencil to list of attachments as needed. |
2703 | VkImageAspectFlags dsAspectFlags = 0; |
2704 | VkClearValue dsClearValue = {}; |
2705 | dsClearValue.depthStencil.depth = clears->getDepthValue(); |
2706 | dsClearValue.depthStencil.stencil = clears->getStencilValue(); |
2707 | if (clears->testDepth() && (renderPassCommands->hasAnyDepthAccess() || !optimizeWithLoadOp)) |
2708 | { |
2709 | dsAspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT; |
2710 | // Explicitly mark a depth write because we are clearing the depth buffer. |
2711 | renderPassCommands->onDepthAccess(access: vk::ResourceAccess::ReadWrite); |
2712 | clears->reset(index: vk::kUnpackedDepthIndex); |
2713 | ++contextVk->getPerfCounters().depthClearAttachments; |
2714 | } |
2715 | |
2716 | if (clears->testStencil() && (renderPassCommands->hasAnyStencilAccess() || !optimizeWithLoadOp)) |
2717 | { |
2718 | dsAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; |
2719 | // Explicitly mark a stencil write because we are clearing the stencil buffer. |
2720 | renderPassCommands->onStencilAccess(access: vk::ResourceAccess::ReadWrite); |
2721 | clears->reset(index: vk::kUnpackedStencilIndex); |
2722 | ++contextVk->getPerfCounters().stencilClearAttachments; |
2723 | } |
2724 | |
2725 | if (dsAspectFlags != 0) |
2726 | { |
2727 | attachments.emplace_back(args: VkClearAttachment{.aspectMask: dsAspectFlags, .colorAttachment: 0, .clearValue: dsClearValue}); |
2728 | |
2729 | // Because we may have changed the depth/stencil access mode, update read only depth/stencil |
2730 | // mode. |
2731 | renderPassCommands->updateDepthStencilReadOnlyMode( |
2732 | dsUsageFlags: contextVk->getDepthStencilAttachmentFlags(), dsAspectFlags); |
2733 | } |
2734 | |
2735 | if (attachments.empty()) |
2736 | { |
2737 | // If called with the intent to definitely clear something with vkCmdClearAttachments, there |
2738 | // must have been something to clear! |
2739 | ASSERT(optimizeWithLoadOp); |
2740 | return; |
2741 | } |
2742 | |
2743 | const uint32_t layerCount = mState.isMultiview() ? 1 : mCurrentFramebufferDesc.getLayerCount(); |
2744 | |
2745 | VkClearRect rect = {}; |
2746 | rect.rect.offset.x = scissoredRenderArea.x; |
2747 | rect.rect.offset.y = scissoredRenderArea.y; |
2748 | rect.rect.extent.width = scissoredRenderArea.width; |
2749 | rect.rect.extent.height = scissoredRenderArea.height; |
2750 | rect.layerCount = layerCount; |
2751 | vk::RenderPassCommandBuffer *renderPassCommandBuffer = &renderPassCommands->getCommandBuffer(); |
2752 | |
2753 | renderPassCommandBuffer->clearAttachments(attachmentCount: static_cast<uint32_t>(attachments.size()), |
2754 | attachments: attachments.data(), rectCount: 1, rects: &rect); |
2755 | return; |
2756 | } |
2757 | |
2758 | void FramebufferVk::clearWithLoadOp(ContextVk *contextVk) |
2759 | { |
2760 | vk::RenderPassCommandBufferHelper *renderPassCommands = |
2761 | &contextVk->getStartedRenderPassCommands(); |
2762 | |
2763 | // Update the render pass loadOps to clear the attachments. |
2764 | vk::PackedAttachmentIndex colorIndexVk(0); |
2765 | for (size_t colorIndexGL : mState.getColorAttachmentsMask()) |
2766 | { |
2767 | if (!mDeferredClears.test(index: colorIndexGL)) |
2768 | { |
2769 | ++colorIndexVk; |
2770 | continue; |
2771 | } |
2772 | |
2773 | ASSERT(!renderPassCommands->hasAnyColorAccess(colorIndexVk)); |
2774 | |
2775 | renderPassCommands->updateRenderPassColorClear(colorIndexVk, colorClearValue: mDeferredClears[colorIndexGL]); |
2776 | |
2777 | mDeferredClears.reset(index: colorIndexGL); |
2778 | |
2779 | ++colorIndexVk; |
2780 | } |
2781 | |
2782 | VkClearValue dsClearValue = {}; |
2783 | dsClearValue.depthStencil.depth = mDeferredClears.getDepthValue(); |
2784 | dsClearValue.depthStencil.stencil = mDeferredClears.getStencilValue(); |
2785 | VkImageAspectFlags dsAspects = 0; |
2786 | |
2787 | if (mDeferredClears.testDepth()) |
2788 | { |
2789 | ASSERT(!renderPassCommands->hasAnyDepthAccess()); |
2790 | dsAspects |= VK_IMAGE_ASPECT_DEPTH_BIT; |
2791 | mDeferredClears.reset(index: vk::kUnpackedDepthIndex); |
2792 | } |
2793 | |
2794 | if (mDeferredClears.testStencil()) |
2795 | { |
2796 | ASSERT(!renderPassCommands->hasAnyStencilAccess()); |
2797 | dsAspects |= VK_IMAGE_ASPECT_STENCIL_BIT; |
2798 | mDeferredClears.reset(index: vk::kUnpackedStencilIndex); |
2799 | } |
2800 | |
2801 | if (dsAspects != 0) |
2802 | { |
2803 | renderPassCommands->updateRenderPassDepthStencilClear(aspectFlags: dsAspects, clearValue: dsClearValue); |
2804 | |
2805 | // The render pass can no longer be in read-only depth/stencil mode. |
2806 | renderPassCommands->updateDepthStencilReadOnlyMode( |
2807 | dsUsageFlags: contextVk->getDepthStencilAttachmentFlags(), dsAspectFlags: dsAspects); |
2808 | } |
2809 | } |
2810 | |
2811 | angle::Result FramebufferVk::getSamplePosition(const gl::Context *context, |
2812 | size_t index, |
2813 | GLfloat *xy) const |
2814 | { |
2815 | int sampleCount = getSamples(); |
2816 | rx::GetSamplePosition(sampleCount, index, xy); |
2817 | return angle::Result::Continue; |
2818 | } |
2819 | |
2820 | angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk, |
2821 | const gl::Rectangle &renderArea, |
2822 | vk::RenderPassCommandBuffer **commandBufferOut, |
2823 | bool *renderPassDescChangedOut) |
2824 | { |
2825 | ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass(RenderPassClosureReason::NewRenderPass)); |
2826 | |
2827 | // Initialize RenderPass info. |
2828 | vk::AttachmentOpsArray renderPassAttachmentOps; |
2829 | vk::PackedClearValuesArray packedClearValues; |
2830 | gl::DrawBufferMask previousUnresolveColorMask = |
2831 | mRenderPassDesc.getColorUnresolveAttachmentMask(); |
2832 | const bool hasDeferredClears = mDeferredClears.any(); |
2833 | const bool previousUnresolveDepth = mRenderPassDesc.hasDepthUnresolveAttachment(); |
2834 | const bool previousUnresolveStencil = mRenderPassDesc.hasStencilUnresolveAttachment(); |
2835 | |
2836 | // Make sure render pass and framebuffer are in agreement w.r.t unresolve attachments. |
2837 | ASSERT(mCurrentFramebufferDesc.getUnresolveAttachmentMask() == |
2838 | MakeUnresolveAttachmentMask(mRenderPassDesc)); |
2839 | |
2840 | // Color attachments. |
2841 | const auto &colorRenderTargets = mRenderTargetCache.getColors(); |
2842 | vk::PackedAttachmentIndex colorIndexVk(0); |
2843 | for (size_t colorIndexGL : mState.getColorAttachmentsMask()) |
2844 | { |
2845 | RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL]; |
2846 | ASSERT(colorRenderTarget); |
2847 | |
2848 | // Color render targets are never entirely transient. Only depth/stencil |
2849 | // multisampled-render-to-texture textures can be so. |
2850 | ASSERT(!colorRenderTarget->isEntirelyTransient()); |
2851 | const vk::RenderPassStoreOp storeOp = colorRenderTarget->isImageTransient() |
2852 | ? vk::RenderPassStoreOp::DontCare |
2853 | : vk::RenderPassStoreOp::Store; |
2854 | |
2855 | if (mDeferredClears.test(index: colorIndexGL)) |
2856 | { |
2857 | renderPassAttachmentOps.setOps(index: colorIndexVk, loadOp: vk::RenderPassLoadOp::Clear, storeOp); |
2858 | packedClearValues.store(index: colorIndexVk, aspectFlags: VK_IMAGE_ASPECT_COLOR_BIT, |
2859 | clearValue: mDeferredClears[colorIndexGL]); |
2860 | mDeferredClears.reset(index: colorIndexGL); |
2861 | } |
2862 | else |
2863 | { |
2864 | const vk::RenderPassLoadOp loadOp = colorRenderTarget->hasDefinedContent() |
2865 | ? vk::RenderPassLoadOp::Load |
2866 | : vk::RenderPassLoadOp::DontCare; |
2867 | |
2868 | renderPassAttachmentOps.setOps(index: colorIndexVk, loadOp, storeOp); |
2869 | packedClearValues.store(index: colorIndexVk, aspectFlags: VK_IMAGE_ASPECT_COLOR_BIT, |
2870 | clearValue: kUninitializedClearValue); |
2871 | } |
2872 | renderPassAttachmentOps.setStencilOps(index: colorIndexVk, loadOp: vk::RenderPassLoadOp::DontCare, |
2873 | storeOp: vk::RenderPassStoreOp::DontCare); |
2874 | |
2875 | // If there's a resolve attachment, and loadOp needs to be LOAD, the multisampled attachment |
2876 | // needs to take its value from the resolve attachment. In this case, an initial subpass is |
2877 | // added for this very purpose which uses the resolve attachment as input attachment. As a |
2878 | // result, loadOp of the multisampled attachment can remain DONT_CARE. |
2879 | // |
2880 | // Note that this only needs to be done if the multisampled image and the resolve attachment |
2881 | // come from the same source. isImageTransient() indicates whether this should happen. |
2882 | if (colorRenderTarget->hasResolveAttachment() && colorRenderTarget->isImageTransient()) |
2883 | { |
2884 | if (renderPassAttachmentOps[colorIndexVk].loadOp == VK_ATTACHMENT_LOAD_OP_LOAD) |
2885 | { |
2886 | renderPassAttachmentOps[colorIndexVk].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; |
2887 | |
2888 | // Update the render pass desc to specify that this attachment should be unresolved. |
2889 | mRenderPassDesc.packColorUnresolveAttachment(colorIndexGL); |
2890 | } |
2891 | else |
2892 | { |
2893 | mRenderPassDesc.removeColorUnresolveAttachment(colorIndexGL); |
2894 | } |
2895 | } |
2896 | else |
2897 | { |
2898 | ASSERT(!mRenderPassDesc.getColorUnresolveAttachmentMask().test(colorIndexGL)); |
2899 | } |
2900 | |
2901 | ++colorIndexVk; |
2902 | } |
2903 | |
2904 | // Depth/stencil attachment. |
2905 | vk::PackedAttachmentIndex depthStencilAttachmentIndex = vk::kAttachmentIndexInvalid; |
2906 | RenderTargetVk *depthStencilRenderTarget = getDepthStencilRenderTarget(); |
2907 | if (depthStencilRenderTarget) |
2908 | { |
2909 | // depth stencil attachment always immediately follows color attachment |
2910 | depthStencilAttachmentIndex = colorIndexVk; |
2911 | |
2912 | vk::RenderPassLoadOp depthLoadOp = vk::RenderPassLoadOp::Load; |
2913 | vk::RenderPassLoadOp stencilLoadOp = vk::RenderPassLoadOp::Load; |
2914 | vk::RenderPassStoreOp depthStoreOp = vk::RenderPassStoreOp::Store; |
2915 | vk::RenderPassStoreOp stencilStoreOp = vk::RenderPassStoreOp::Store; |
2916 | |
2917 | // If the image data was previously discarded (with no update in between), don't attempt to |
2918 | // load the image. Additionally, if the multisampled image data is transient and there is |
2919 | // no resolve attachment, there's no data to load. The latter is the case with |
2920 | // depth/stencil texture attachments per GL_EXT_multisampled_render_to_texture2. |
2921 | if (!depthStencilRenderTarget->hasDefinedContent() || |
2922 | depthStencilRenderTarget->isEntirelyTransient()) |
2923 | { |
2924 | depthLoadOp = vk::RenderPassLoadOp::DontCare; |
2925 | } |
2926 | if (!depthStencilRenderTarget->hasDefinedStencilContent() || |
2927 | depthStencilRenderTarget->isEntirelyTransient()) |
2928 | { |
2929 | stencilLoadOp = vk::RenderPassLoadOp::DontCare; |
2930 | } |
2931 | |
2932 | // If depth/stencil image is transient, no need to store its data at the end of the render |
2933 | // pass. |
2934 | if (depthStencilRenderTarget->isImageTransient()) |
2935 | { |
2936 | depthStoreOp = vk::RenderPassStoreOp::DontCare; |
2937 | stencilStoreOp = vk::RenderPassStoreOp::DontCare; |
2938 | } |
2939 | |
2940 | if (mDeferredClears.testDepth() || mDeferredClears.testStencil()) |
2941 | { |
2942 | VkClearValue clearValue = {}; |
2943 | |
2944 | if (mDeferredClears.testDepth()) |
2945 | { |
2946 | depthLoadOp = vk::RenderPassLoadOp::Clear; |
2947 | clearValue.depthStencil.depth = mDeferredClears.getDepthValue(); |
2948 | mDeferredClears.reset(index: vk::kUnpackedDepthIndex); |
2949 | } |
2950 | |
2951 | if (mDeferredClears.testStencil()) |
2952 | { |
2953 | stencilLoadOp = vk::RenderPassLoadOp::Clear; |
2954 | clearValue.depthStencil.stencil = mDeferredClears.getStencilValue(); |
2955 | mDeferredClears.reset(index: vk::kUnpackedStencilIndex); |
2956 | } |
2957 | |
2958 | // Note the aspect is only depth here. That's intentional. |
2959 | packedClearValues.store(index: depthStencilAttachmentIndex, aspectFlags: VK_IMAGE_ASPECT_DEPTH_BIT, |
2960 | clearValue); |
2961 | } |
2962 | else |
2963 | { |
2964 | // Note the aspect is only depth here. That's intentional. |
2965 | packedClearValues.store(index: depthStencilAttachmentIndex, aspectFlags: VK_IMAGE_ASPECT_DEPTH_BIT, |
2966 | clearValue: kUninitializedClearValue); |
2967 | } |
2968 | |
2969 | const angle::Format &format = depthStencilRenderTarget->getImageIntendedFormat(); |
2970 | // If the format we picked has stencil but user did not ask for it due to hardware |
2971 | // limitations, use DONT_CARE for load/store. The same logic for depth follows. |
2972 | if (format.stencilBits == 0) |
2973 | { |
2974 | stencilLoadOp = vk::RenderPassLoadOp::DontCare; |
2975 | stencilStoreOp = vk::RenderPassStoreOp::DontCare; |
2976 | } |
2977 | if (format.depthBits == 0) |
2978 | { |
2979 | depthLoadOp = vk::RenderPassLoadOp::DontCare; |
2980 | depthStoreOp = vk::RenderPassStoreOp::DontCare; |
2981 | } |
2982 | |
2983 | // Similar to color attachments, if there's a resolve attachment and the multisampled image |
2984 | // is transient, depth/stencil data need to be unresolved in an initial subpass. |
2985 | if (depthStencilRenderTarget->hasResolveAttachment() && |
2986 | depthStencilRenderTarget->isImageTransient()) |
2987 | { |
2988 | const bool unresolveDepth = depthLoadOp == vk::RenderPassLoadOp::Load; |
2989 | const bool unresolveStencil = stencilLoadOp == vk::RenderPassLoadOp::Load; |
2990 | |
2991 | if (unresolveDepth) |
2992 | { |
2993 | depthLoadOp = vk::RenderPassLoadOp::DontCare; |
2994 | } |
2995 | |
2996 | if (unresolveStencil) |
2997 | { |
2998 | stencilLoadOp = vk::RenderPassLoadOp::DontCare; |
2999 | |
3000 | // If VK_EXT_shader_stencil_export is not supported, stencil unresolve is done |
3001 | // through a method that requires stencil to have been cleared. |
3002 | if (!contextVk->getRenderer()->getFeatures().supportsShaderStencilExport.enabled) |
3003 | { |
3004 | stencilLoadOp = vk::RenderPassLoadOp::Clear; |
3005 | |
3006 | // Note the aspect is only depth here. That's intentional. |
3007 | VkClearValue clearValue = packedClearValues[depthStencilAttachmentIndex]; |
3008 | clearValue.depthStencil.stencil = 0; |
3009 | packedClearValues.store(index: depthStencilAttachmentIndex, aspectFlags: VK_IMAGE_ASPECT_DEPTH_BIT, |
3010 | clearValue); |
3011 | } |
3012 | } |
3013 | |
3014 | if (unresolveDepth || unresolveStencil) |
3015 | { |
3016 | mRenderPassDesc.packDepthStencilUnresolveAttachment(unresolveDepth, |
3017 | unresolveStencil); |
3018 | } |
3019 | else |
3020 | { |
3021 | mRenderPassDesc.removeDepthStencilUnresolveAttachment(); |
3022 | } |
3023 | } |
3024 | |
3025 | renderPassAttachmentOps.setOps(index: depthStencilAttachmentIndex, loadOp: depthLoadOp, storeOp: depthStoreOp); |
3026 | renderPassAttachmentOps.setStencilOps(index: depthStencilAttachmentIndex, loadOp: stencilLoadOp, |
3027 | storeOp: stencilStoreOp); |
3028 | } |
3029 | |
3030 | // If render pass description is changed, the previous render pass desc is no longer compatible. |
3031 | // Tell the context so that the graphics pipelines can be recreated. |
3032 | // |
3033 | // Note that render passes are compatible only if the differences are in loadOp/storeOp values, |
3034 | // or the existence of resolve attachments in single subpass render passes. The modification |
3035 | // here can add/remove a subpass, or modify its input attachments. |
3036 | gl::DrawBufferMask unresolveColorMask = mRenderPassDesc.getColorUnresolveAttachmentMask(); |
3037 | const bool unresolveDepth = mRenderPassDesc.hasDepthUnresolveAttachment(); |
3038 | const bool unresolveStencil = mRenderPassDesc.hasStencilUnresolveAttachment(); |
3039 | const bool unresolveChanged = previousUnresolveColorMask != unresolveColorMask || |
3040 | previousUnresolveDepth != unresolveDepth || |
3041 | previousUnresolveStencil != unresolveStencil; |
3042 | if (unresolveChanged) |
3043 | { |
3044 | // Make sure framebuffer is recreated. |
3045 | releaseCurrentFramebuffer(contextVk); |
3046 | |
3047 | mCurrentFramebufferDesc.updateUnresolveMask(unresolveMask: MakeUnresolveAttachmentMask(desc: mRenderPassDesc)); |
3048 | } |
3049 | |
3050 | vk::MaybeImagelessFramebuffer framebuffer = {}; |
3051 | ANGLE_TRY( |
3052 | getFramebuffer(contextVk, &framebuffer, nullptr, nullptr, SwapchainResolveMode::Disabled)); |
3053 | |
3054 | // If deferred clears were used in the render pass, the render area must cover the whole |
3055 | // framebuffer. |
3056 | ASSERT(!hasDeferredClears || renderArea == getRotatedCompleteRenderArea(contextVk)); |
3057 | |
3058 | ANGLE_TRY(contextVk->beginNewRenderPass( |
3059 | framebuffer, renderArea, mRenderPassDesc, renderPassAttachmentOps, colorIndexVk, |
3060 | depthStencilAttachmentIndex, packedClearValues, commandBufferOut)); |
3061 | mLastRenderPassQueueSerial = contextVk->getStartedRenderPassCommands().getQueueSerial(); |
3062 | |
3063 | // Add the images to the renderpass tracking list (through onColorDraw). |
3064 | vk::PackedAttachmentIndex colorAttachmentIndex(0); |
3065 | for (size_t colorIndexGL : mState.getColorAttachmentsMask()) |
3066 | { |
3067 | RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL]; |
3068 | colorRenderTarget->onColorDraw(contextVk, framebufferLayerCount: mCurrentFramebufferDesc.getLayerCount(), |
3069 | index: colorAttachmentIndex); |
3070 | ++colorAttachmentIndex; |
3071 | } |
3072 | |
3073 | if (depthStencilRenderTarget) |
3074 | { |
3075 | // This must be called after hasDefined*Content() since it will set content to valid. If |
3076 | // the attachment ends up not used in the render pass, contents will be marked undefined at |
3077 | // endRenderPass. The actual layout determination is also deferred until the same time. |
3078 | depthStencilRenderTarget->onDepthStencilDraw(contextVk, |
3079 | framebufferLayerCount: mCurrentFramebufferDesc.getLayerCount()); |
3080 | } |
3081 | |
3082 | const bool anyUnresolve = unresolveColorMask.any() || unresolveDepth || unresolveStencil; |
3083 | if (anyUnresolve) |
3084 | { |
3085 | // Unresolve attachments if any. |
3086 | UtilsVk::UnresolveParameters params; |
3087 | params.unresolveColorMask = unresolveColorMask; |
3088 | params.unresolveDepth = unresolveDepth; |
3089 | params.unresolveStencil = unresolveStencil; |
3090 | |
3091 | ANGLE_TRY(contextVk->getUtils().unresolve(contextVk, this, params)); |
3092 | |
3093 | // The unresolve subpass has only one draw call. |
3094 | ANGLE_TRY(contextVk->startNextSubpass()); |
3095 | } |
3096 | |
3097 | if (unresolveChanged || anyUnresolve) |
3098 | { |
3099 | contextVk->onDrawFramebufferRenderPassDescChange(framebufferVk: this, renderPassDescChangedOut); |
3100 | } |
3101 | |
3102 | return angle::Result::Continue; |
3103 | } |
3104 | |
3105 | gl::Rectangle FramebufferVk::getRenderArea(ContextVk *contextVk) const |
3106 | { |
3107 | if (hasDeferredClears()) |
3108 | { |
3109 | return getRotatedCompleteRenderArea(contextVk); |
3110 | } |
3111 | else |
3112 | { |
3113 | return getRotatedScissoredRenderArea(contextVk); |
3114 | } |
3115 | } |
3116 | |
3117 | void FramebufferVk::updateActiveColorMasks(size_t colorIndexGL, bool r, bool g, bool b, bool a) |
3118 | { |
3119 | gl::BlendStateExt::ColorMaskStorage::SetValueIndexed( |
3120 | index: colorIndexGL, value: gl::BlendStateExt::PackColorMask(red: r, green: g, blue: b, alpha: a), |
3121 | target: &mActiveColorComponentMasksForClear); |
3122 | } |
3123 | |
3124 | const gl::DrawBufferMask &FramebufferVk::getEmulatedAlphaAttachmentMask() const |
3125 | { |
3126 | return mEmulatedAlphaAttachmentMask; |
3127 | } |
3128 | |
3129 | angle::Result FramebufferVk::readPixelsImpl(ContextVk *contextVk, |
3130 | const gl::Rectangle &area, |
3131 | const PackPixelsParams &packPixelsParams, |
3132 | VkImageAspectFlagBits copyAspectFlags, |
3133 | RenderTargetVk *renderTarget, |
3134 | void *pixels) |
3135 | { |
3136 | ANGLE_TRACE_EVENT0("gpu.angle", "FramebufferVk::readPixelsImpl"); |
3137 | gl::LevelIndex levelGL = renderTarget->getLevelIndex(); |
3138 | uint32_t layer = renderTarget->getLayerIndex(); |
3139 | return renderTarget->getImageForCopy().readPixels(contextVk, area, packPixelsParams, |
3140 | copyAspectFlags, levelGL, layer, pixels); |
3141 | } |
3142 | |
3143 | gl::Extents FramebufferVk::getReadImageExtents() const |
3144 | { |
3145 | RenderTargetVk *readRenderTarget = mRenderTargetCache.getColorRead(state: mState); |
3146 | return readRenderTarget->getExtents(); |
3147 | } |
3148 | |
3149 | // Return the framebuffer's non-rotated render area. This is a gl::Rectangle that is based on the |
3150 | // dimensions of the framebuffer, IS NOT rotated, and IS NOT y-flipped |
3151 | gl::Rectangle FramebufferVk::getNonRotatedCompleteRenderArea() const |
3152 | { |
3153 | const gl::Box &dimensions = mState.getDimensions(); |
3154 | return gl::Rectangle(0, 0, dimensions.width, dimensions.height); |
3155 | } |
3156 | |
3157 | // Return the framebuffer's rotated render area. This is a gl::Rectangle that is based on the |
3158 | // dimensions of the framebuffer, IS ROTATED for the draw FBO, and IS NOT y-flipped |
3159 | // |
3160 | // Note: Since the rectangle is not scissored (i.e. x and y are guaranteed to be zero), only the |
3161 | // width and height must be swapped if the rotation is 90 or 270 degrees. |
3162 | gl::Rectangle FramebufferVk::getRotatedCompleteRenderArea(ContextVk *contextVk) const |
3163 | { |
3164 | gl::Rectangle renderArea = getNonRotatedCompleteRenderArea(); |
3165 | if (contextVk->isRotatedAspectRatioForDrawFBO()) |
3166 | { |
3167 | // The surface is rotated 90/270 degrees. This changes the aspect ratio of the surface. |
3168 | std::swap(x&: renderArea.width, y&: renderArea.height); |
3169 | } |
3170 | return renderArea; |
3171 | } |
3172 | |
3173 | // Return the framebuffer's scissored and rotated render area. This is a gl::Rectangle that is |
3174 | // based on the dimensions of the framebuffer, is clipped to the scissor, IS ROTATED and IS |
3175 | // Y-FLIPPED for the draw FBO. |
3176 | // |
3177 | // Note: Since the rectangle is scissored, it must be fully rotated, and not just have the width |
3178 | // and height swapped. |
3179 | gl::Rectangle FramebufferVk::getRotatedScissoredRenderArea(ContextVk *contextVk) const |
3180 | { |
3181 | const gl::Rectangle renderArea = getNonRotatedCompleteRenderArea(); |
3182 | bool invertViewport = contextVk->isViewportFlipEnabledForDrawFBO(); |
3183 | gl::Rectangle scissoredArea = ClipRectToScissor(glState: contextVk->getState(), rect: renderArea, invertY: false); |
3184 | gl::Rectangle rotatedScissoredArea; |
3185 | RotateRectangle(rotation: contextVk->getRotationDrawFramebuffer(), flipY: invertViewport, framebufferWidth: renderArea.width, |
3186 | framebufferHeight: renderArea.height, incoming: scissoredArea, outgoing: &rotatedScissoredArea); |
3187 | return rotatedScissoredArea; |
3188 | } |
3189 | |
3190 | GLint FramebufferVk::getSamples() const |
3191 | { |
3192 | const gl::FramebufferAttachment *lastAttachment = nullptr; |
3193 | |
3194 | for (size_t colorIndexGL : mState.getEnabledDrawBuffers() & mState.getColorAttachmentsMask()) |
3195 | { |
3196 | const gl::FramebufferAttachment *color = mState.getColorAttachment(colorAttachment: colorIndexGL); |
3197 | ASSERT(color); |
3198 | |
3199 | if (color->isRenderToTexture()) |
3200 | { |
3201 | return color->getSamples(); |
3202 | } |
3203 | |
3204 | lastAttachment = color; |
3205 | } |
3206 | const gl::FramebufferAttachment *depthStencil = mState.getDepthOrStencilAttachment(); |
3207 | if (depthStencil) |
3208 | { |
3209 | if (depthStencil->isRenderToTexture()) |
3210 | { |
3211 | return depthStencil->getSamples(); |
3212 | } |
3213 | lastAttachment = depthStencil; |
3214 | } |
3215 | |
3216 | // If none of the attachments are multisampled-render-to-texture, take the sample count from the |
3217 | // last attachment (any would have worked, as they would all have the same sample count). |
3218 | return std::max(a: lastAttachment ? lastAttachment->getSamples() : 1, b: 1); |
3219 | } |
3220 | |
3221 | angle::Result FramebufferVk::flushDeferredClears(ContextVk *contextVk) |
3222 | { |
3223 | if (mDeferredClears.empty()) |
3224 | { |
3225 | return angle::Result::Continue; |
3226 | } |
3227 | |
3228 | return contextVk->startRenderPass(renderArea: getRotatedCompleteRenderArea(contextVk), commandBufferOut: nullptr, renderPassDescChangedOut: nullptr); |
3229 | } |
3230 | |
3231 | void FramebufferVk::switchToFramebufferFetchMode(ContextVk *contextVk, bool hasFramebufferFetch) |
3232 | { |
3233 | // The switch happens once, and is permanent. |
3234 | if (mCurrentFramebufferDesc.hasFramebufferFetch() == hasFramebufferFetch) |
3235 | { |
3236 | return; |
3237 | } |
3238 | |
3239 | // Make sure framebuffer is recreated. |
3240 | releaseCurrentFramebuffer(contextVk); |
3241 | mCurrentFramebufferDesc.setFramebufferFetchMode(hasFramebufferFetch); |
3242 | |
3243 | mRenderPassDesc.setFramebufferFetchMode(hasFramebufferFetch); |
3244 | contextVk->onDrawFramebufferRenderPassDescChange(framebufferVk: this, renderPassDescChangedOut: nullptr); |
3245 | |
3246 | // Clear the framebuffer cache, as none of the old framebuffers are usable. |
3247 | if (contextVk->getFeatures().permanentlySwitchToFramebufferFetchMode.enabled) |
3248 | { |
3249 | ASSERT(hasFramebufferFetch); |
3250 | releaseCurrentFramebuffer(contextVk); |
3251 | } |
3252 | } |
3253 | |
3254 | bool FramebufferVk::updateLegacyDither(ContextVk *contextVk) |
3255 | { |
3256 | if (contextVk->getFeatures().supportsLegacyDithering.enabled && |
3257 | mRenderPassDesc.isLegacyDitherEnabled() != contextVk->isDitherEnabled()) |
3258 | { |
3259 | mRenderPassDesc.setLegacyDither(contextVk->isDitherEnabled()); |
3260 | return true; |
3261 | } |
3262 | |
3263 | return false; |
3264 | } |
3265 | } // namespace rx |
3266 |
Definitions
- kUninitializedClearValue
- kEmulatedAlphaValue
- HasSrcBlitFeature
- HasDstBlitFeature
- AreSrcAndDstColorChannelsBlitCompatible
- AreSrcAndDstFormatsIdentical
- AreSrcAndDstDepthStencilChannelsBlitCompatible
- EarlyAdjustFlipYForPreRotation
- AdjustBlitAreaForPreRotation
- AdjustDimensionsAndFlipForPreRotation
- AdjustBlitResolveParametersForResolve
- AdjustBlitResolveParametersForPreRotation
- HasResolveAttachment
- MakeUnresolveAttachmentMask
- IsAnyAttachment3DWithoutAllLayers
- FramebufferVk
- ~FramebufferVk
- destroy
- insertCache
- discard
- invalidate
- invalidateSub
- clear
- clearImpl
- clearBufferfv
- clearBufferuiv
- clearBufferiv
- clearBufferfi
- getImplementationColorReadFormat
- readPixels
- getDepthStencilRenderTarget
- getColorDrawRenderTarget
- getColorReadRenderTarget
- getReadPixelsRenderTarget
- getReadPixelsAspectFlags
- blitWithCommand
- blit
- updateColorResolveAttachment
- removeColorResolveAttachment
- releaseCurrentFramebuffer
- updateLayerCount
- resolveColorWithSubpass
- resolveColorWithCommand
- checkStatus
- invalidateImpl
- updateColorAttachment
- updateDepthStencilAttachment
- updateDepthStencilAttachmentSerial
- flushColorAttachmentUpdates
- flushDepthStencilAttachmentUpdates
- syncState
- updateRenderPassDesc
- getAttachmentsAndRenderTargets
- getFramebuffer
- mergeClearsWithDeferredClears
- clearWithDraw
- getCorrectedColorClearValue
- redeferClears
- redeferClearsForReadFramebuffer
- redeferClearsImpl
- clearWithCommand
- clearWithLoadOp
- getSamplePosition
- startNewRenderPass
- getRenderArea
- updateActiveColorMasks
- getEmulatedAlphaAttachmentMask
- readPixelsImpl
- getReadImageExtents
- getNonRotatedCompleteRenderArea
- getRotatedCompleteRenderArea
- getRotatedScissoredRenderArea
- getSamples
- flushDeferredClears
- switchToFramebufferFetchMode
Learn more about Flutter for embedded and desktop on industrialflutter.com