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 // ImageVk.cpp:
7 // Implements the class methods for ImageVk.
8 //
9
10 #include "libANGLE/renderer/vulkan/ImageVk.h"
11
12 #include "common/debug.h"
13 #include "libANGLE/Context.h"
14 #include "libANGLE/Display.h"
15 #include "libANGLE/renderer/vulkan/ContextVk.h"
16 #include "libANGLE/renderer/vulkan/DisplayVk.h"
17 #include "libANGLE/renderer/vulkan/RenderbufferVk.h"
18 #include "libANGLE/renderer/vulkan/TextureVk.h"
19 #include "libANGLE/renderer/vulkan/vk_utils.h"
20
21 namespace rx
22 {
23
ImageVk(const egl::ImageState & state,const gl::Context * context)24 ImageVk::ImageVk(const egl::ImageState &state, const gl::Context *context)
25 : ImageImpl(state), mImageLevel(0), mOwnsImage(false), mImage(nullptr), mContext(context)
26 {}
27
~ImageVk()28 ImageVk::~ImageVk() {}
29
onDestroy(const egl::Display * display)30 void ImageVk::onDestroy(const egl::Display *display)
31 {
32 DisplayVk *displayVk = vk::GetImpl(display);
33 RendererVk *renderer = displayVk->getRenderer();
34
35 if (mImage != nullptr && mOwnsImage)
36 {
37 mImage->releaseImage(renderer);
38 mImage->releaseStagingBuffer(renderer);
39 SafeDelete(mImage);
40 }
41 else if (egl::IsExternalImageTarget(mState.target))
42 {
43 ASSERT(mState.source != nullptr);
44 ExternalImageSiblingVk *externalImageSibling =
45 GetImplAs<ExternalImageSiblingVk>(GetAs<egl::ExternalImageSibling>(mState.source));
46 externalImageSibling->release(renderer);
47 mImage = nullptr;
48 }
49 }
50
initialize(const egl::Display * display)51 egl::Error ImageVk::initialize(const egl::Display *display)
52 {
53 if (egl::IsTextureTarget(mState.target))
54 {
55 TextureVk *textureVk = GetImplAs<TextureVk>(GetAs<gl::Texture>(mState.source));
56
57 // Make sure the texture has created its backing storage
58 ASSERT(mContext != nullptr);
59 ContextVk *contextVk = vk::GetImpl(mContext);
60 ANGLE_TRY(ResultToEGL(
61 textureVk->ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels)));
62
63 mImage = &textureVk->getImage();
64
65 // The staging buffer for a texture source should already be initialized
66
67 mOwnsImage = false;
68
69 mImageTextureType = mState.imageIndex.getType();
70 mImageLevel = mState.imageIndex.getLevelIndex();
71 mImageLayer = mState.imageIndex.hasLayer() ? mState.imageIndex.getLayerIndex() : 0;
72 }
73 else
74 {
75 RendererVk *renderer = nullptr;
76 if (egl::IsRenderbufferTarget(mState.target))
77 {
78 RenderbufferVk *renderbufferVk =
79 GetImplAs<RenderbufferVk>(GetAs<gl::Renderbuffer>(mState.source));
80 mImage = renderbufferVk->getImage();
81
82 ASSERT(mContext != nullptr);
83 renderer = vk::GetImpl(mContext)->getRenderer();
84 }
85 else if (egl::IsExternalImageTarget(mState.target))
86 {
87 const ExternalImageSiblingVk *externalImageSibling =
88 GetImplAs<ExternalImageSiblingVk>(GetAs<egl::ExternalImageSibling>(mState.source));
89 mImage = externalImageSibling->getImage();
90
91 ASSERT(mContext == nullptr);
92 renderer = vk::GetImpl(display)->getRenderer();
93 }
94 else
95 {
96 UNREACHABLE();
97 return egl::EglBadAccess();
98 }
99
100 // Make sure a staging buffer is ready to use to upload data
101 mImage->initStagingBuffer(renderer, mImage->getFormat(), vk::kStagingBufferFlags,
102 vk::kStagingBufferSize);
103
104 mOwnsImage = false;
105
106 mImageTextureType = gl::TextureType::_2D;
107 mImageLevel = 0;
108 mImageLayer = 0;
109 }
110
111 // mContext is no longer needed, make sure it's not used by accident.
112 mContext = nullptr;
113
114 return egl::NoError();
115 }
116
orphan(const gl::Context * context,egl::ImageSibling * sibling)117 angle::Result ImageVk::orphan(const gl::Context *context, egl::ImageSibling *sibling)
118 {
119 if (sibling == mState.source)
120 {
121 if (egl::IsTextureTarget(mState.target))
122 {
123 TextureVk *textureVk = GetImplAs<TextureVk>(GetAs<gl::Texture>(mState.source));
124 ASSERT(mImage == &textureVk->getImage());
125 textureVk->releaseOwnershipOfImage(context);
126 mOwnsImage = true;
127 }
128 else if (egl::IsRenderbufferTarget(mState.target))
129 {
130 RenderbufferVk *renderbufferVk =
131 GetImplAs<RenderbufferVk>(GetAs<gl::Renderbuffer>(mState.source));
132 ASSERT(mImage == renderbufferVk->getImage());
133 renderbufferVk->releaseOwnershipOfImage(context);
134 mOwnsImage = true;
135 }
136 else
137 {
138 ANGLE_VK_UNREACHABLE(vk::GetImpl(context));
139 return angle::Result::Stop;
140 }
141 }
142
143 // Grab a fence from the releasing context to know when the image is no longer used
144 ASSERT(context != nullptr);
145 ContextVk *contextVk = vk::GetImpl(context);
146
147 // Flush the context to make sure the fence has been submitted.
148 ANGLE_TRY(contextVk->flushImpl(nullptr));
149
150 return angle::Result::Continue;
151 }
152
153 } // namespace rx
154