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