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 // RenderbufferVk.cpp:
7 // Implements the class methods for RenderbufferVk.
8 //
9
10 #include "libANGLE/renderer/vulkan/RenderbufferVk.h"
11
12 #include "libANGLE/Context.h"
13 #include "libANGLE/Image.h"
14 #include "libANGLE/renderer/vulkan/ContextVk.h"
15 #include "libANGLE/renderer/vulkan/ImageVk.h"
16 #include "libANGLE/renderer/vulkan/TextureVk.h"
17 #include "libANGLE/renderer/vulkan/vk_renderer.h"
18
19 namespace rx
20 {
21 namespace
22 {
23 angle::SubjectIndex kRenderbufferImageSubjectIndex = 0;
24 } // namespace
25
RenderbufferVk(const gl::RenderbufferState & state)26 RenderbufferVk::RenderbufferVk(const gl::RenderbufferState &state)
27 : RenderbufferImpl(state),
28 mOwnsImage(false),
29 mImage(nullptr),
30 mImageObserverBinding(this, kRenderbufferImageSubjectIndex)
31 {}
32
~RenderbufferVk()33 RenderbufferVk::~RenderbufferVk() {}
34
onDestroy(const gl::Context * context)35 void RenderbufferVk::onDestroy(const gl::Context *context)
36 {
37 ContextVk *contextVk = vk::GetImpl(context);
38 releaseAndDeleteImage(contextVk);
39 }
40
setStorageImpl(const gl::Context * context,GLsizei samples,GLenum internalformat,GLsizei width,GLsizei height,gl::MultisamplingMode mode)41 angle::Result RenderbufferVk::setStorageImpl(const gl::Context *context,
42 GLsizei samples,
43 GLenum internalformat,
44 GLsizei width,
45 GLsizei height,
46 gl::MultisamplingMode mode)
47 {
48 ContextVk *contextVk = vk::GetImpl(context);
49 vk::Renderer *renderer = contextVk->getRenderer();
50 const vk::Format &format = renderer->getFormat(internalformat);
51 angle::FormatID textureFormatID = format.getActualRenderableImageFormatID();
52
53 if (!mOwnsImage)
54 {
55 releaseAndDeleteImage(contextVk);
56 }
57
58 if (mImage != nullptr && mImage->valid())
59 {
60 // Check against the state if we need to recreate the storage.
61 if (internalformat != mState.getFormat().info->internalFormat ||
62 width != mState.getWidth() || height != mState.getHeight() ||
63 samples != mState.getSamples() || mode != mState.getMultisamplingMode())
64 {
65 releaseImage(contextVk);
66 }
67 }
68
69 if ((mImage != nullptr && mImage->valid()) || width == 0 || height == 0)
70 {
71 return angle::Result::Continue;
72 }
73
74 if (mImage == nullptr)
75 {
76 mImage = new vk::ImageHelper();
77 mOwnsImage = true;
78 mImageSiblingSerial = {};
79 mImageObserverBinding.bind(mImage);
80 mImageViews.init(renderer);
81 }
82
83 const angle::Format &textureFormat = format.getActualRenderableImageFormat();
84 const bool isDepthStencilFormat = textureFormat.hasDepthOrStencilBits();
85 ASSERT(textureFormat.redBits > 0 || isDepthStencilFormat);
86
87 const bool isRenderToTexture = mode == gl::MultisamplingMode::MultisampledRenderToTexture;
88 const bool hasRenderToTextureEXT =
89 renderer->getFeatures().supportsMultisampledRenderToSingleSampled.enabled;
90
91 // Transfer and sampled usage are used for various utilities such as readback or blit.
92 VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
93 VK_IMAGE_USAGE_SAMPLED_BIT;
94
95 // Renderbuffer's normal usage is as framebuffer attachment.
96 usage |= isDepthStencilFormat ? VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
97 : VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
98
99 // When used to emulate multisampled render to texture, it can be read as input attachment.
100 if (isRenderToTexture && !hasRenderToTextureEXT)
101 {
102 usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
103 }
104
105 // For framebuffer fetch and advanced blend emulation, color will be read as input attachment.
106 // For depth/stencil framebuffer fetch, depth/stencil will also be read as input attachment.
107 if (!isDepthStencilFormat ||
108 renderer->getFeatures().supportsShaderFramebufferFetchDepthStencil.enabled)
109 {
110 usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
111 }
112
113 VkImageCreateFlags createFlags = vk::kVkImageCreateFlagsNone;
114 if (isRenderToTexture &&
115 renderer->getFeatures().supportsMultisampledRenderToSingleSampled.enabled)
116 {
117 createFlags |= VK_IMAGE_CREATE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_BIT_EXT;
118 }
119
120 if (contextVk->getFeatures().limitSampleCountTo2.enabled)
121 {
122 samples = std::min(samples, 2);
123 }
124
125 const uint32_t imageSamples = isRenderToTexture ? 1 : samples;
126
127 bool robustInit = contextVk->isRobustResourceInitEnabled();
128
129 VkExtent3D extents = {static_cast<uint32_t>(width), static_cast<uint32_t>(height), 1u};
130 ANGLE_TRY(mImage->initExternal(
131 contextVk, gl::TextureType::_2D, extents, format.getIntendedFormatID(), textureFormatID,
132 imageSamples, usage, createFlags, vk::ImageLayout::Undefined, nullptr, gl::LevelIndex(0), 1,
133 1, robustInit, false, vk::YcbcrConversionDesc{}, nullptr));
134
135 VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
136 ANGLE_TRY(contextVk->initImageAllocation(mImage, false, renderer->getMemoryProperties(), flags,
137 vk::MemoryAllocationType::RenderBufferStorageImage));
138
139 // If multisampled render to texture, an implicit multisampled image is created which is used as
140 // the color or depth/stencil attachment. At the end of the render pass, this image is
141 // automatically resolved into |mImage| and its contents are discarded.
142 if (isRenderToTexture && !hasRenderToTextureEXT)
143 {
144 mMultisampledImageViews.init(renderer);
145
146 ANGLE_TRY(mMultisampledImage.initImplicitMultisampledRenderToTexture(
147 contextVk, false, renderer->getMemoryProperties(), gl::TextureType::_2D, samples,
148 *mImage, mImage->getExtents(), robustInit));
149
150 mRenderTarget.init(&mMultisampledImage, &mMultisampledImageViews, mImage, &mImageViews,
151 mImageSiblingSerial, gl::LevelIndex(0), 0, 1,
152 RenderTargetTransience::MultisampledTransient);
153 }
154 else
155 {
156 mRenderTarget.init(mImage, &mImageViews, nullptr, nullptr, mImageSiblingSerial,
157 gl::LevelIndex(0), 0, 1, RenderTargetTransience::Default);
158 }
159
160 return angle::Result::Continue;
161 }
162
setStorage(const gl::Context * context,GLenum internalformat,GLsizei width,GLsizei height)163 angle::Result RenderbufferVk::setStorage(const gl::Context *context,
164 GLenum internalformat,
165 GLsizei width,
166 GLsizei height)
167 {
168 // The ES 3.0 spec(section 4.4.2.1) states that RenderbufferStorage is equivalent to calling
169 // RenderbufferStorageMultisample with samples equal to zero.
170 return setStorageImpl(context, 0, internalformat, width, height,
171 gl::MultisamplingMode::Regular);
172 }
173
setStorageMultisample(const gl::Context * context,GLsizei samples,GLenum internalformat,GLsizei width,GLsizei height,gl::MultisamplingMode mode)174 angle::Result RenderbufferVk::setStorageMultisample(const gl::Context *context,
175 GLsizei samples,
176 GLenum internalformat,
177 GLsizei width,
178 GLsizei height,
179 gl::MultisamplingMode mode)
180 {
181 return setStorageImpl(context, samples, internalformat, width, height, mode);
182 }
183
setStorageEGLImageTarget(const gl::Context * context,egl::Image * image)184 angle::Result RenderbufferVk::setStorageEGLImageTarget(const gl::Context *context,
185 egl::Image *image)
186 {
187 ContextVk *contextVk = vk::GetImpl(context);
188 vk::Renderer *renderer = contextVk->getRenderer();
189
190 ANGLE_TRY(contextVk->getShareGroup()->lockDefaultContextsPriority(contextVk));
191
192 releaseAndDeleteImage(contextVk);
193
194 ImageVk *imageVk = vk::GetImpl(image);
195 mImage = imageVk->getImage();
196 mOwnsImage = false;
197 mImageSiblingSerial = imageVk->generateSiblingSerial();
198 mImageObserverBinding.bind(mImage);
199 mImageViews.init(renderer);
200
201 // Update ImageViewHelper's colorspace related state
202 EGLenum imageColorspaceAttribute = image->getColorspaceAttribute();
203 if (imageColorspaceAttribute != EGL_GL_COLORSPACE_DEFAULT_EXT)
204 {
205 egl::ImageColorspace imageColorspace =
206 (imageColorspaceAttribute == EGL_GL_COLORSPACE_SRGB_KHR) ? egl::ImageColorspace::SRGB
207 : egl::ImageColorspace::Linear;
208 ASSERT(mImage != nullptr);
209 mImageViews.updateEglImageColorspace(*mImage, imageColorspace);
210 }
211
212 // Transfer the image to this queue if needed
213 if (mImage->isQueueFamilyChangeNeccesary(contextVk->getDeviceQueueIndex()))
214 {
215 vk::OutsideRenderPassCommandBuffer *commandBuffer;
216 vk::CommandBufferAccess access;
217 access.onExternalAcquireRelease(mImage);
218 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
219
220 const vk::Format &vkFormat =
221 renderer->getFormat(image->getFormat().info->sizedInternalFormat);
222 const angle::Format &textureFormat = vkFormat.getActualRenderableImageFormat();
223 VkImageAspectFlags aspect = vk::GetFormatAspectFlags(textureFormat);
224
225 mImage->changeLayoutAndQueue(contextVk, aspect, vk::ImageLayout::ColorWrite,
226 contextVk->getDeviceQueueIndex(), commandBuffer);
227
228 ANGLE_TRY(contextVk->onEGLImageQueueChange());
229 }
230
231 mRenderTarget.init(mImage, &mImageViews, nullptr, nullptr, mImageSiblingSerial,
232 imageVk->getImageLevel(), imageVk->getImageLayer(), 1,
233 RenderTargetTransience::Default);
234
235 return angle::Result::Continue;
236 }
237
copyRenderbufferSubData(const gl::Context * context,const gl::Renderbuffer * srcBuffer,GLint srcLevel,GLint srcX,GLint srcY,GLint srcZ,GLint dstLevel,GLint dstX,GLint dstY,GLint dstZ,GLsizei srcWidth,GLsizei srcHeight,GLsizei srcDepth)238 angle::Result RenderbufferVk::copyRenderbufferSubData(const gl::Context *context,
239 const gl::Renderbuffer *srcBuffer,
240 GLint srcLevel,
241 GLint srcX,
242 GLint srcY,
243 GLint srcZ,
244 GLint dstLevel,
245 GLint dstX,
246 GLint dstY,
247 GLint dstZ,
248 GLsizei srcWidth,
249 GLsizei srcHeight,
250 GLsizei srcDepth)
251 {
252 RenderbufferVk *sourceVk = vk::GetImpl(srcBuffer);
253
254 // Make sure the source/destination targets are initialized and all staged updates are flushed.
255 ANGLE_TRY(sourceVk->ensureImageInitialized(context));
256 ANGLE_TRY(ensureImageInitialized(context));
257
258 return vk::ImageHelper::CopyImageSubData(context, sourceVk->getImage(), srcLevel, srcX, srcY,
259 srcZ, mImage, dstLevel, dstX, dstY, dstZ, srcWidth,
260 srcHeight, srcDepth);
261 }
262
copyTextureSubData(const gl::Context * context,const gl::Texture * srcTexture,GLint srcLevel,GLint srcX,GLint srcY,GLint srcZ,GLint dstLevel,GLint dstX,GLint dstY,GLint dstZ,GLsizei srcWidth,GLsizei srcHeight,GLsizei srcDepth)263 angle::Result RenderbufferVk::copyTextureSubData(const gl::Context *context,
264 const gl::Texture *srcTexture,
265 GLint srcLevel,
266 GLint srcX,
267 GLint srcY,
268 GLint srcZ,
269 GLint dstLevel,
270 GLint dstX,
271 GLint dstY,
272 GLint dstZ,
273 GLsizei srcWidth,
274 GLsizei srcHeight,
275 GLsizei srcDepth)
276 {
277 ContextVk *contextVk = vk::GetImpl(context);
278 TextureVk *sourceVk = vk::GetImpl(srcTexture);
279
280 // Make sure the source/destination targets are initialized and all staged updates are flushed.
281 ANGLE_TRY(sourceVk->ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
282 ANGLE_TRY(ensureImageInitialized(context));
283
284 return vk::ImageHelper::CopyImageSubData(context, &sourceVk->getImage(), srcLevel, srcX, srcY,
285 srcZ, mImage, dstLevel, dstX, dstY, dstZ, srcWidth,
286 srcHeight, srcDepth);
287 }
288
getAttachmentRenderTarget(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex,GLsizei samples,FramebufferAttachmentRenderTarget ** rtOut)289 angle::Result RenderbufferVk::getAttachmentRenderTarget(const gl::Context *context,
290 GLenum binding,
291 const gl::ImageIndex &imageIndex,
292 GLsizei samples,
293 FramebufferAttachmentRenderTarget **rtOut)
294 {
295 ASSERT(mImage && mImage->valid());
296 *rtOut = &mRenderTarget;
297 return angle::Result::Continue;
298 }
299
initializeContents(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex)300 angle::Result RenderbufferVk::initializeContents(const gl::Context *context,
301 GLenum binding,
302 const gl::ImageIndex &imageIndex)
303 {
304 // Note: stageSubresourceRobustClear only uses the intended format to count channels.
305 mImage->stageRobustResourceClear(imageIndex);
306 return mImage->flushAllStagedUpdates(vk::GetImpl(context));
307 }
308
releaseOwnershipOfImage(const gl::Context * context)309 void RenderbufferVk::releaseOwnershipOfImage(const gl::Context *context)
310 {
311 ContextVk *contextVk = vk::GetImpl(context);
312
313 ASSERT(!mImageSiblingSerial.valid());
314
315 mOwnsImage = false;
316 releaseAndDeleteImage(contextVk);
317 }
318
releaseAndDeleteImage(ContextVk * contextVk)319 void RenderbufferVk::releaseAndDeleteImage(ContextVk *contextVk)
320 {
321 releaseImage(contextVk);
322 SafeDelete(mImage);
323 mImageObserverBinding.bind(nullptr);
324 }
325
releaseImage(ContextVk * contextVk)326 void RenderbufferVk::releaseImage(ContextVk *contextVk)
327 {
328 vk::Renderer *renderer = contextVk->getRenderer();
329 if (mImage == nullptr)
330 {
331 ASSERT(mImageViews.isImageViewGarbageEmpty() &&
332 mMultisampledImageViews.isImageViewGarbageEmpty());
333 }
334 else
335 {
336 mRenderTarget.releaseImageAndViews(contextVk);
337 mImageViews.release(renderer, mImage->getResourceUse());
338 mMultisampledImageViews.release(renderer, mImage->getResourceUse());
339 }
340
341 if (mImage && mOwnsImage)
342 {
343 mImage->releaseImageFromShareContexts(renderer, contextVk, mImageSiblingSerial);
344 mImage->releaseStagedUpdates(renderer);
345 }
346 else
347 {
348 if (mImage)
349 {
350 mImage->finalizeImageLayoutInShareContexts(renderer, contextVk, mImageSiblingSerial);
351 }
352 mImage = nullptr;
353 mImageObserverBinding.bind(nullptr);
354 }
355
356 if (mMultisampledImage.valid())
357 {
358 mMultisampledImage.releaseImageFromShareContexts(renderer, contextVk, mImageSiblingSerial);
359 }
360 }
361
getImplementationSizedFormat() const362 const gl::InternalFormat &RenderbufferVk::getImplementationSizedFormat() const
363 {
364 GLenum internalFormat = mImage->getActualFormat().glInternalFormat;
365 return gl::GetSizedInternalFormatInfo(internalFormat);
366 }
367
getColorReadFormat(const gl::Context * context)368 GLenum RenderbufferVk::getColorReadFormat(const gl::Context *context)
369 {
370 const gl::InternalFormat &sizedFormat = getImplementationSizedFormat();
371 return sizedFormat.format;
372 }
373
getColorReadType(const gl::Context * context)374 GLenum RenderbufferVk::getColorReadType(const gl::Context *context)
375 {
376 const gl::InternalFormat &sizedFormat = getImplementationSizedFormat();
377 return sizedFormat.type;
378 }
379
getRenderbufferImage(const gl::Context * context,const gl::PixelPackState & packState,gl::Buffer * packBuffer,GLenum format,GLenum type,void * pixels)380 angle::Result RenderbufferVk::getRenderbufferImage(const gl::Context *context,
381 const gl::PixelPackState &packState,
382 gl::Buffer *packBuffer,
383 GLenum format,
384 GLenum type,
385 void *pixels)
386 {
387 // Storage not defined.
388 if (!mImage || !mImage->valid())
389 {
390 return angle::Result::Continue;
391 }
392
393 ContextVk *contextVk = vk::GetImpl(context);
394 ANGLE_TRY(mImage->flushAllStagedUpdates(contextVk));
395
396 gl::MaybeOverrideLuminance(format, type, getColorReadFormat(context),
397 getColorReadType(context));
398
399 return mImage->readPixelsForGetImage(contextVk, packState, packBuffer, gl::LevelIndex(0), 0, 0,
400 format, type, pixels);
401 }
402
ensureImageInitialized(const gl::Context * context)403 angle::Result RenderbufferVk::ensureImageInitialized(const gl::Context *context)
404 {
405 ANGLE_TRY(setStorage(context, mState.getFormat().info->internalFormat, mState.getWidth(),
406 mState.getHeight()));
407
408 return mImage->flushAllStagedUpdates(vk::GetImpl(context));
409 }
410
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)411 void RenderbufferVk::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
412 {
413 ASSERT(index == kRenderbufferImageSubjectIndex &&
414 (message == angle::SubjectMessage::SubjectChanged ||
415 message == angle::SubjectMessage::InitializationComplete));
416
417 // Forward the notification to the parent class that the staging buffer changed.
418 if (message == angle::SubjectMessage::SubjectChanged)
419 {
420 onStateChange(angle::SubjectMessage::SubjectChanged);
421 }
422 }
423 } // namespace rx
424