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 "dawn_native/Device.h" 18 #include "dawn_native/Texture.h" 19 #include "dawn_native/ValidationUtils_autogen.h" 20 21 namespace dawn_native { 22 23 namespace { 24 25 class ErrorSwapChain : public SwapChainBase { 26 public: ErrorSwapChain(DeviceBase * device)27 ErrorSwapChain(DeviceBase* device) : SwapChainBase(device, ObjectBase::kError) { 28 } 29 30 private: GetNextTextureImpl(const TextureDescriptor *)31 TextureBase* GetNextTextureImpl(const TextureDescriptor*) override { 32 UNREACHABLE(); 33 } 34 OnBeforePresent(TextureBase * texture)35 void OnBeforePresent(TextureBase* texture) override { 36 UNREACHABLE(); 37 } 38 }; 39 40 } // anonymous namespace 41 ValidateSwapChainDescriptor(const DeviceBase * device,const SwapChainDescriptor * descriptor)42 MaybeError ValidateSwapChainDescriptor(const DeviceBase* device, 43 const SwapChainDescriptor* descriptor) { 44 if (descriptor->implementation == 0) { 45 return DAWN_VALIDATION_ERROR("Null implementation for the swapchain"); 46 } 47 48 DawnSwapChainImplementation* impl = 49 reinterpret_cast<DawnSwapChainImplementation*>(descriptor->implementation); 50 51 if (!impl->Init || !impl->Destroy || !impl->Configure || !impl->GetNextTexture || 52 !impl->Present) { 53 return DAWN_VALIDATION_ERROR("Implementation is incomplete"); 54 } 55 56 return {}; 57 } 58 59 // SwapChain 60 SwapChainBase(DeviceBase * device,const SwapChainDescriptor * descriptor)61 SwapChainBase::SwapChainBase(DeviceBase* device, const SwapChainDescriptor* descriptor) 62 : ObjectBase(device), 63 mImplementation( 64 *reinterpret_cast<DawnSwapChainImplementation*>(descriptor->implementation)) { 65 } 66 SwapChainBase(DeviceBase * device,ObjectBase::ErrorTag tag)67 SwapChainBase::SwapChainBase(DeviceBase* device, ObjectBase::ErrorTag tag) 68 : ObjectBase(device, tag) { 69 } 70 ~SwapChainBase()71 SwapChainBase::~SwapChainBase() { 72 if (!IsError()) { 73 const auto& im = GetImplementation(); 74 im.Destroy(im.userData); 75 } 76 } 77 78 // static MakeError(DeviceBase * device)79 SwapChainBase* SwapChainBase::MakeError(DeviceBase* device) { 80 return new ErrorSwapChain(device); 81 } 82 Configure(dawn::TextureFormat format,dawn::TextureUsageBit allowedUsage,uint32_t width,uint32_t height)83 void SwapChainBase::Configure(dawn::TextureFormat format, 84 dawn::TextureUsageBit allowedUsage, 85 uint32_t width, 86 uint32_t height) { 87 if (GetDevice()->ConsumedError(ValidateConfigure(format, allowedUsage, width, height))) { 88 return; 89 } 90 ASSERT(!IsError()); 91 92 allowedUsage |= dawn::TextureUsageBit::Present; 93 94 mFormat = format; 95 mAllowedUsage = allowedUsage; 96 mWidth = width; 97 mHeight = height; 98 mImplementation.Configure(mImplementation.userData, static_cast<DawnTextureFormat>(format), 99 static_cast<DawnTextureUsageBit>(allowedUsage), width, height); 100 } 101 GetNextTexture()102 TextureBase* SwapChainBase::GetNextTexture() { 103 if (GetDevice()->ConsumedError(ValidateGetNextTexture())) { 104 return TextureBase::MakeError(GetDevice()); 105 } 106 ASSERT(!IsError()); 107 108 TextureDescriptor descriptor; 109 descriptor.dimension = dawn::TextureDimension::e2D; 110 descriptor.size.width = mWidth; 111 descriptor.size.height = mHeight; 112 descriptor.size.depth = 1; 113 descriptor.arrayLayerCount = 1; 114 descriptor.sampleCount = 1; 115 descriptor.format = mFormat; 116 descriptor.mipLevelCount = 1; 117 descriptor.usage = mAllowedUsage; 118 119 auto* texture = GetNextTextureImpl(&descriptor); 120 mLastNextTexture = texture; 121 return texture; 122 } 123 Present(TextureBase * texture)124 void SwapChainBase::Present(TextureBase* texture) { 125 if (GetDevice()->ConsumedError(ValidatePresent(texture))) { 126 return; 127 } 128 ASSERT(!IsError()); 129 130 OnBeforePresent(texture); 131 132 mImplementation.Present(mImplementation.userData); 133 } 134 GetImplementation()135 const DawnSwapChainImplementation& SwapChainBase::GetImplementation() { 136 ASSERT(!IsError()); 137 return mImplementation; 138 } 139 ValidateConfigure(dawn::TextureFormat format,dawn::TextureUsageBit allowedUsage,uint32_t width,uint32_t height) const140 MaybeError SwapChainBase::ValidateConfigure(dawn::TextureFormat format, 141 dawn::TextureUsageBit allowedUsage, 142 uint32_t width, 143 uint32_t height) const { 144 DAWN_TRY(GetDevice()->ValidateObject(this)); 145 146 DAWN_TRY(ValidateTextureUsageBit(allowedUsage)); 147 DAWN_TRY(ValidateTextureFormat(format)); 148 149 if (width == 0 || height == 0) { 150 return DAWN_VALIDATION_ERROR("Swap chain cannot be configured to zero size"); 151 } 152 153 return {}; 154 } 155 ValidateGetNextTexture() const156 MaybeError SwapChainBase::ValidateGetNextTexture() const { 157 DAWN_TRY(GetDevice()->ValidateObject(this)); 158 159 if (mWidth == 0) { 160 // If width is 0, it implies swap chain has never been configured 161 return DAWN_VALIDATION_ERROR("Swap chain needs to be configured before GetNextTexture"); 162 } 163 164 return {}; 165 } 166 ValidatePresent(TextureBase * texture) const167 MaybeError SwapChainBase::ValidatePresent(TextureBase* texture) const { 168 DAWN_TRY(GetDevice()->ValidateObject(this)); 169 DAWN_TRY(GetDevice()->ValidateObject(texture)); 170 171 // This also checks that the texture is valid since mLastNextTexture is always valid. 172 if (texture != mLastNextTexture) { 173 return DAWN_VALIDATION_ERROR( 174 "Tried to present something other than the last NextTexture"); 175 } 176 177 return {}; 178 } 179 180 } // namespace dawn_native 181