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