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