• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "dawn_native/SwapChain.h"
16 
17 #include "common/Constants.h"
18 #include "dawn_native/Adapter.h"
19 #include "dawn_native/Device.h"
20 #include "dawn_native/ObjectType_autogen.h"
21 #include "dawn_native/Surface.h"
22 #include "dawn_native/Texture.h"
23 #include "dawn_native/ValidationUtils_autogen.h"
24 
25 namespace dawn_native {
26 
27     namespace {
28 
29         class ErrorSwapChain final : public SwapChainBase {
30           public:
ErrorSwapChain(DeviceBase * device)31             ErrorSwapChain(DeviceBase* device) : SwapChainBase(device, ObjectBase::kError) {
32             }
33 
34           private:
APIConfigure(wgpu::TextureFormat format,wgpu::TextureUsage allowedUsage,uint32_t width,uint32_t height)35             void APIConfigure(wgpu::TextureFormat format,
36                               wgpu::TextureUsage allowedUsage,
37                               uint32_t width,
38                               uint32_t height) override {
39                 GetDevice()->ConsumedError(
40                     DAWN_FORMAT_VALIDATION_ERROR("%s is an error swapchain.", this));
41             }
42 
APIGetCurrentTextureView()43             TextureViewBase* APIGetCurrentTextureView() override {
44                 GetDevice()->ConsumedError(
45                     DAWN_FORMAT_VALIDATION_ERROR("%s is an error swapchain.", this));
46                 return TextureViewBase::MakeError(GetDevice());
47             }
48 
APIPresent()49             void APIPresent() override {
50                 GetDevice()->ConsumedError(
51                     DAWN_FORMAT_VALIDATION_ERROR("%s is an error swapchain.", this));
52             }
53         };
54 
55     }  // anonymous namespace
56 
ValidateSwapChainDescriptor(const DeviceBase * device,const Surface * surface,const SwapChainDescriptor * descriptor)57     MaybeError ValidateSwapChainDescriptor(const DeviceBase* device,
58                                            const Surface* surface,
59                                            const SwapChainDescriptor* descriptor) {
60         if (descriptor->implementation != 0) {
61             DAWN_INVALID_IF(surface != nullptr,
62                             "Exactly one of surface or implementation must be set");
63 
64             DawnSwapChainImplementation* impl =
65                 reinterpret_cast<DawnSwapChainImplementation*>(descriptor->implementation);
66 
67             DAWN_INVALID_IF(!impl->Init || !impl->Destroy || !impl->Configure ||
68                                 !impl->GetNextTexture || !impl->Present,
69                             "Implementation is incomplete");
70 
71         } else {
72             DAWN_INVALID_IF(surface == nullptr,
73                             "At least one of surface or implementation must be set");
74 
75             DAWN_TRY(ValidatePresentMode(descriptor->presentMode));
76 
77             // TODO(crbug.com/dawn/160): Lift this restriction once
78             // wgpu::Instance::GetPreferredSurfaceFormat is implemented.
79             DAWN_INVALID_IF(descriptor->format != wgpu::TextureFormat::BGRA8Unorm,
80                             "Format (%s) is not %s, which is (currently) the only accepted format.",
81                             descriptor->format, wgpu::TextureFormat::BGRA8Unorm);
82 
83             DAWN_INVALID_IF(descriptor->usage != wgpu::TextureUsage::RenderAttachment,
84                             "Usage (%s) is not %s, which is (currently) the only accepted usage.",
85                             descriptor->usage, wgpu::TextureUsage::RenderAttachment);
86 
87             DAWN_INVALID_IF(descriptor->width == 0 || descriptor->height == 0,
88                             "Swap Chain size (width: %u, height: %u) is empty.", descriptor->width,
89                             descriptor->height);
90 
91             DAWN_INVALID_IF(
92                 descriptor->width > device->GetLimits().v1.maxTextureDimension2D ||
93                     descriptor->height > device->GetLimits().v1.maxTextureDimension2D,
94                 "Swap Chain size (width: %u, height: %u) is greater than the maximum 2D texture "
95                 "size (width: %u, height: %u).",
96                 descriptor->width, descriptor->height, device->GetLimits().v1.maxTextureDimension2D,
97                 device->GetLimits().v1.maxTextureDimension2D);
98         }
99 
100         return {};
101     }
102 
GetSwapChainBaseTextureDescriptor(NewSwapChainBase * swapChain)103     TextureDescriptor GetSwapChainBaseTextureDescriptor(NewSwapChainBase* swapChain) {
104         TextureDescriptor desc;
105         desc.usage = swapChain->GetUsage();
106         desc.dimension = wgpu::TextureDimension::e2D;
107         desc.size = {swapChain->GetWidth(), swapChain->GetHeight(), 1};
108         desc.format = swapChain->GetFormat();
109         desc.mipLevelCount = 1;
110         desc.sampleCount = 1;
111 
112         return desc;
113     }
114 
115     // SwapChainBase
116 
SwapChainBase(DeviceBase * device)117     SwapChainBase::SwapChainBase(DeviceBase* device) : ApiObjectBase(device, kLabelNotImplemented) {
118         TrackInDevice();
119     }
120 
SwapChainBase(DeviceBase * device,ObjectBase::ErrorTag tag)121     SwapChainBase::SwapChainBase(DeviceBase* device, ObjectBase::ErrorTag tag)
122         : ApiObjectBase(device, tag) {
123     }
124 
~SwapChainBase()125     SwapChainBase::~SwapChainBase() {
126     }
127 
DestroyImpl()128     void SwapChainBase::DestroyImpl() {
129     }
130 
131     // static
MakeError(DeviceBase * device)132     SwapChainBase* SwapChainBase::MakeError(DeviceBase* device) {
133         return new ErrorSwapChain(device);
134     }
135 
GetType() const136     ObjectType SwapChainBase::GetType() const {
137         return ObjectType::SwapChain;
138     }
139 
140     // OldSwapChainBase
141 
OldSwapChainBase(DeviceBase * device,const SwapChainDescriptor * descriptor)142     OldSwapChainBase::OldSwapChainBase(DeviceBase* device, const SwapChainDescriptor* descriptor)
143         : SwapChainBase(device),
144           mImplementation(
145               *reinterpret_cast<DawnSwapChainImplementation*>(descriptor->implementation)) {
146     }
147 
~OldSwapChainBase()148     OldSwapChainBase::~OldSwapChainBase() {
149         if (!IsError()) {
150             const auto& im = GetImplementation();
151             im.Destroy(im.userData);
152         }
153     }
154 
APIConfigure(wgpu::TextureFormat format,wgpu::TextureUsage allowedUsage,uint32_t width,uint32_t height)155     void OldSwapChainBase::APIConfigure(wgpu::TextureFormat format,
156                                         wgpu::TextureUsage allowedUsage,
157                                         uint32_t width,
158                                         uint32_t height) {
159         if (GetDevice()->ConsumedError(ValidateConfigure(format, allowedUsage, width, height))) {
160             return;
161         }
162         ASSERT(!IsError());
163 
164         allowedUsage |= wgpu::TextureUsage::Present;
165 
166         mFormat = format;
167         mAllowedUsage = allowedUsage;
168         mWidth = width;
169         mHeight = height;
170         mImplementation.Configure(mImplementation.userData, static_cast<WGPUTextureFormat>(format),
171                                   static_cast<WGPUTextureUsage>(allowedUsage), width, height);
172     }
173 
APIGetCurrentTextureView()174     TextureViewBase* OldSwapChainBase::APIGetCurrentTextureView() {
175         if (GetDevice()->ConsumedError(ValidateGetCurrentTextureView())) {
176             return TextureViewBase::MakeError(GetDevice());
177         }
178         ASSERT(!IsError());
179 
180         // Return the same current texture view until Present is called.
181         if (mCurrentTextureView != nullptr) {
182             // Calling GetCurrentTextureView always returns a new reference so add it even when
183             // reuse the existing texture view.
184             mCurrentTextureView->Reference();
185             return mCurrentTextureView.Get();
186         }
187 
188         // Create the backing texture and the view.
189         TextureDescriptor descriptor;
190         descriptor.dimension = wgpu::TextureDimension::e2D;
191         descriptor.size.width = mWidth;
192         descriptor.size.height = mHeight;
193         descriptor.size.depthOrArrayLayers = 1;
194         descriptor.sampleCount = 1;
195         descriptor.format = mFormat;
196         descriptor.mipLevelCount = 1;
197         descriptor.usage = mAllowedUsage;
198 
199         // Get the texture but remove the external refcount because it is never passed outside
200         // of dawn_native
201         mCurrentTexture = AcquireRef(GetNextTextureImpl(&descriptor));
202 
203         mCurrentTextureView = mCurrentTexture->APICreateView();
204         return mCurrentTextureView.Get();
205     }
206 
APIPresent()207     void OldSwapChainBase::APIPresent() {
208         if (GetDevice()->ConsumedError(ValidatePresent())) {
209             return;
210         }
211         ASSERT(!IsError());
212 
213         if (GetDevice()->ConsumedError(OnBeforePresent(mCurrentTextureView.Get()))) {
214             return;
215         }
216 
217         mImplementation.Present(mImplementation.userData);
218 
219         mCurrentTexture = nullptr;
220         mCurrentTextureView = nullptr;
221     }
222 
GetImplementation()223     const DawnSwapChainImplementation& OldSwapChainBase::GetImplementation() {
224         ASSERT(!IsError());
225         return mImplementation;
226     }
227 
ValidateConfigure(wgpu::TextureFormat format,wgpu::TextureUsage allowedUsage,uint32_t width,uint32_t height) const228     MaybeError OldSwapChainBase::ValidateConfigure(wgpu::TextureFormat format,
229                                                    wgpu::TextureUsage allowedUsage,
230                                                    uint32_t width,
231                                                    uint32_t height) const {
232         DAWN_TRY(GetDevice()->ValidateIsAlive());
233         DAWN_TRY(GetDevice()->ValidateObject(this));
234 
235         DAWN_TRY(ValidateTextureUsage(allowedUsage));
236         DAWN_TRY(ValidateTextureFormat(format));
237 
238         DAWN_INVALID_IF(width == 0 || height == 0,
239                         "Configuration size (width: %u, height: %u) for %s is empty.", width,
240                         height, this);
241 
242         return {};
243     }
244 
ValidateGetCurrentTextureView() const245     MaybeError OldSwapChainBase::ValidateGetCurrentTextureView() const {
246         DAWN_TRY(GetDevice()->ValidateIsAlive());
247         DAWN_TRY(GetDevice()->ValidateObject(this));
248 
249         // If width is 0, it implies swap chain has never been configured
250         DAWN_INVALID_IF(mWidth == 0, "%s was not configured prior to calling GetNextTexture.",
251                         this);
252 
253         return {};
254     }
255 
ValidatePresent() const256     MaybeError OldSwapChainBase::ValidatePresent() const {
257         DAWN_TRY(GetDevice()->ValidateIsAlive());
258         DAWN_TRY(GetDevice()->ValidateObject(this));
259 
260         DAWN_INVALID_IF(
261             mCurrentTextureView == nullptr,
262             "GetCurrentTextureView was not called on %s this frame prior to calling Present.",
263             this);
264 
265         return {};
266     }
267 
268     // Implementation of NewSwapChainBase
269 
NewSwapChainBase(DeviceBase * device,Surface * surface,const SwapChainDescriptor * descriptor)270     NewSwapChainBase::NewSwapChainBase(DeviceBase* device,
271                                        Surface* surface,
272                                        const SwapChainDescriptor* descriptor)
273         : SwapChainBase(device),
274           mAttached(false),
275           mWidth(descriptor->width),
276           mHeight(descriptor->height),
277           mFormat(descriptor->format),
278           mUsage(descriptor->usage),
279           mPresentMode(descriptor->presentMode),
280           mSurface(surface) {
281     }
282 
~NewSwapChainBase()283     NewSwapChainBase::~NewSwapChainBase() {
284         if (mCurrentTextureView != nullptr) {
285             ASSERT(mCurrentTextureView->GetTexture()->GetTextureState() ==
286                    TextureBase::TextureState::Destroyed);
287         }
288 
289         ASSERT(!mAttached);
290     }
291 
DetachFromSurface()292     void NewSwapChainBase::DetachFromSurface() {
293         if (mAttached) {
294             DetachFromSurfaceImpl();
295             mSurface = nullptr;
296             mAttached = false;
297         }
298     }
299 
SetIsAttached()300     void NewSwapChainBase::SetIsAttached() {
301         mAttached = true;
302     }
303 
APIConfigure(wgpu::TextureFormat format,wgpu::TextureUsage allowedUsage,uint32_t width,uint32_t height)304     void NewSwapChainBase::APIConfigure(wgpu::TextureFormat format,
305                                         wgpu::TextureUsage allowedUsage,
306                                         uint32_t width,
307                                         uint32_t height) {
308         GetDevice()->ConsumedError(
309             DAWN_FORMAT_VALIDATION_ERROR("Configure is invalid for surface-based swapchains."));
310     }
311 
APIGetCurrentTextureView()312     TextureViewBase* NewSwapChainBase::APIGetCurrentTextureView() {
313         if (GetDevice()->ConsumedError(ValidateGetCurrentTextureView())) {
314             return TextureViewBase::MakeError(GetDevice());
315         }
316 
317         if (mCurrentTextureView != nullptr) {
318             // Calling GetCurrentTextureView always returns a new reference so add it even when
319             // reusing the existing texture view.
320             mCurrentTextureView->Reference();
321             return mCurrentTextureView.Get();
322         }
323 
324         TextureViewBase* view = nullptr;
325         if (GetDevice()->ConsumedError(GetCurrentTextureViewImpl(), &view)) {
326             return TextureViewBase::MakeError(GetDevice());
327         }
328 
329         // Check that the return texture view matches exactly what was given for this descriptor.
330         ASSERT(view->GetTexture()->GetFormat().format == mFormat);
331         ASSERT(IsSubset(mUsage, view->GetTexture()->GetUsage()));
332         ASSERT(view->GetLevelCount() == 1);
333         ASSERT(view->GetLayerCount() == 1);
334         ASSERT(view->GetDimension() == wgpu::TextureViewDimension::e2D);
335         ASSERT(view->GetTexture()->GetMipLevelVirtualSize(view->GetBaseMipLevel()).width == mWidth);
336         ASSERT(view->GetTexture()->GetMipLevelVirtualSize(view->GetBaseMipLevel()).height ==
337                mHeight);
338 
339         mCurrentTextureView = view;
340         return view;
341     }
342 
APIPresent()343     void NewSwapChainBase::APIPresent() {
344         if (GetDevice()->ConsumedError(ValidatePresent())) {
345             return;
346         }
347 
348         if (GetDevice()->ConsumedError(PresentImpl())) {
349             return;
350         }
351 
352         ASSERT(mCurrentTextureView->GetTexture()->GetTextureState() ==
353                TextureBase::TextureState::Destroyed);
354         mCurrentTextureView = nullptr;
355     }
356 
GetWidth() const357     uint32_t NewSwapChainBase::GetWidth() const {
358         return mWidth;
359     }
360 
GetHeight() const361     uint32_t NewSwapChainBase::GetHeight() const {
362         return mHeight;
363     }
364 
GetFormat() const365     wgpu::TextureFormat NewSwapChainBase::GetFormat() const {
366         return mFormat;
367     }
368 
GetUsage() const369     wgpu::TextureUsage NewSwapChainBase::GetUsage() const {
370         return mUsage;
371     }
372 
GetPresentMode() const373     wgpu::PresentMode NewSwapChainBase::GetPresentMode() const {
374         return mPresentMode;
375     }
376 
GetSurface() const377     Surface* NewSwapChainBase::GetSurface() const {
378         return mSurface;
379     }
380 
IsAttached() const381     bool NewSwapChainBase::IsAttached() const {
382         return mAttached;
383     }
384 
GetBackendType() const385     wgpu::BackendType NewSwapChainBase::GetBackendType() const {
386         return GetDevice()->GetAdapter()->GetBackendType();
387     }
388 
ValidatePresent() const389     MaybeError NewSwapChainBase::ValidatePresent() const {
390         DAWN_TRY(GetDevice()->ValidateIsAlive());
391         DAWN_TRY(GetDevice()->ValidateObject(this));
392 
393         DAWN_INVALID_IF(!mAttached, "Cannot call Present called on detached %s.", this);
394 
395         DAWN_INVALID_IF(
396             mCurrentTextureView == nullptr,
397             "GetCurrentTextureView was not called on %s this frame prior to calling Present.",
398             this);
399 
400         return {};
401     }
402 
ValidateGetCurrentTextureView() const403     MaybeError NewSwapChainBase::ValidateGetCurrentTextureView() const {
404         DAWN_TRY(GetDevice()->ValidateIsAlive());
405         DAWN_TRY(GetDevice()->ValidateObject(this));
406 
407         DAWN_INVALID_IF(!mAttached, "Cannot call GetCurrentTextureView on detached %s.", this);
408 
409         return {};
410     }
411 
412 }  // namespace dawn_native
413