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