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