2018-07-18 02:40:26 -07:00
|
|
|
// Copyright 2017 The Dawn Authors
|
2017-07-19 15:41:17 -07:00
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
2022-02-04 09:07:46 -08:00
|
|
|
#include "dawn/native/SwapChain.h"
|
2017-07-19 15:41:17 -07:00
|
|
|
|
2022-02-04 04:51:25 -08:00
|
|
|
#include "dawn/common/Constants.h"
|
2022-02-04 09:07:46 -08:00
|
|
|
#include "dawn/native/Device.h"
|
|
|
|
#include "dawn/native/ObjectType_autogen.h"
|
2023-05-01 09:39:04 -07:00
|
|
|
#include "dawn/native/PhysicalDevice.h"
|
2022-02-04 09:07:46 -08:00
|
|
|
#include "dawn/native/Surface.h"
|
|
|
|
#include "dawn/native/Texture.h"
|
|
|
|
#include "dawn/native/ValidationUtils_autogen.h"
|
2017-07-19 15:41:17 -07:00
|
|
|
|
2022-01-12 01:17:35 -08:00
|
|
|
namespace dawn::native {
|
2017-07-19 15:41:17 -07:00
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
class ErrorSwapChain final : public SwapChainBase {
|
|
|
|
public:
|
2023-05-26 03:32:17 -07:00
|
|
|
explicit ErrorSwapChain(DeviceBase* device, const SwapChainDescriptor* desc)
|
|
|
|
: SwapChainBase(device, desc, ObjectBase::kError) {}
|
2022-05-01 07:40:55 -07:00
|
|
|
|
|
|
|
private:
|
2023-05-23 05:30:36 -07:00
|
|
|
ResultOrError<Ref<TextureBase>> GetCurrentTextureImpl() override { UNREACHABLE(); }
|
2023-04-07 06:30:50 -07:00
|
|
|
MaybeError PresentImpl() override { UNREACHABLE(); }
|
|
|
|
void DetachFromSurfaceImpl() override { UNREACHABLE(); }
|
2022-05-01 07:40:55 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
|
|
|
MaybeError ValidateSwapChainDescriptor(const DeviceBase* device,
|
|
|
|
const Surface* surface,
|
|
|
|
const SwapChainDescriptor* descriptor) {
|
2023-04-05 03:13:01 -07:00
|
|
|
DAWN_INVALID_IF(surface->IsError(), "[Surface] is invalid.");
|
2022-05-01 07:40:55 -07:00
|
|
|
|
2023-04-05 03:13:01 -07:00
|
|
|
DAWN_TRY(ValidatePresentMode(descriptor->presentMode));
|
2020-01-23 09:20:38 -08:00
|
|
|
|
2022-03-25 06:18:46 -07:00
|
|
|
// TODO(crbug.com/dawn/160): Lift this restriction once wgpu::Instance::GetPreferredSurfaceFormat is
|
|
|
|
// implemented.
|
|
|
|
// TODO(dawn:286):
|
2022-06-08 12:52:42 -07:00
|
|
|
#if DAWN_PLATFORM_IS(ANDROID)
|
2023-04-05 03:13:01 -07:00
|
|
|
constexpr wgpu::TextureFormat kRequireSwapChainFormat = wgpu::TextureFormat::RGBA8Unorm;
|
2022-03-25 06:18:46 -07:00
|
|
|
#else
|
2023-04-05 03:13:01 -07:00
|
|
|
constexpr wgpu::TextureFormat kRequireSwapChainFormat = wgpu::TextureFormat::BGRA8Unorm;
|
2022-06-08 12:52:42 -07:00
|
|
|
#endif // !DAWN_PLATFORM_IS(ANDROID)
|
2023-04-05 03:13:01 -07:00
|
|
|
DAWN_INVALID_IF(descriptor->format != kRequireSwapChainFormat,
|
|
|
|
"Format (%s) is not %s, which is (currently) the only accepted format.",
|
|
|
|
descriptor->format, kRequireSwapChainFormat);
|
2019-02-15 03:15:58 -08:00
|
|
|
|
2023-04-20 13:42:05 -07:00
|
|
|
if (device->HasFeature(Feature::SurfaceCapabilities)) {
|
|
|
|
wgpu::TextureUsage validUsage;
|
|
|
|
DAWN_TRY_ASSIGN(validUsage, device->GetSupportedSurfaceUsage(surface));
|
|
|
|
DAWN_INVALID_IF(
|
|
|
|
(descriptor->usage | validUsage) != validUsage,
|
|
|
|
"Usage (%s) is not supported, %s are (currently) the only accepted usage flags.",
|
|
|
|
descriptor->usage, validUsage);
|
|
|
|
} else {
|
|
|
|
DAWN_INVALID_IF(descriptor->usage != wgpu::TextureUsage::RenderAttachment,
|
|
|
|
"Usage (%s) is not %s, which is (currently) the only accepted usage. Other "
|
|
|
|
"usage flags require enabling %s",
|
|
|
|
descriptor->usage, wgpu::TextureUsage::RenderAttachment,
|
|
|
|
wgpu::FeatureName::SurfaceCapabilities);
|
|
|
|
}
|
2020-01-25 02:05:40 -08:00
|
|
|
|
2023-04-05 03:13:01 -07:00
|
|
|
DAWN_INVALID_IF(descriptor->width == 0 || descriptor->height == 0,
|
|
|
|
"Swap Chain size (width: %u, height: %u) is empty.", descriptor->width,
|
|
|
|
descriptor->height);
|
2022-05-01 07:40:55 -07:00
|
|
|
|
2023-04-05 03:13:01 -07:00
|
|
|
DAWN_INVALID_IF(
|
|
|
|
descriptor->width > device->GetLimits().v1.maxTextureDimension2D ||
|
|
|
|
descriptor->height > device->GetLimits().v1.maxTextureDimension2D,
|
|
|
|
"Swap Chain size (width: %u, height: %u) is greater than the maximum 2D texture "
|
|
|
|
"size (width: %u, height: %u).",
|
|
|
|
descriptor->width, descriptor->height, device->GetLimits().v1.maxTextureDimension2D,
|
|
|
|
device->GetLimits().v1.maxTextureDimension2D);
|
2020-01-25 02:05:40 -08:00
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
return {};
|
|
|
|
}
|
2017-07-19 15:41:17 -07:00
|
|
|
|
2023-04-07 06:30:50 -07:00
|
|
|
TextureDescriptor GetSwapChainBaseTextureDescriptor(SwapChainBase* swapChain) {
|
2022-05-01 07:40:55 -07:00
|
|
|
TextureDescriptor desc;
|
|
|
|
desc.usage = swapChain->GetUsage();
|
|
|
|
desc.dimension = wgpu::TextureDimension::e2D;
|
|
|
|
desc.size = {swapChain->GetWidth(), swapChain->GetHeight(), 1};
|
|
|
|
desc.format = swapChain->GetFormat();
|
|
|
|
desc.mipLevelCount = 1;
|
|
|
|
desc.sampleCount = 1;
|
2019-02-15 03:15:58 -08:00
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
return desc;
|
|
|
|
}
|
2017-07-19 15:41:17 -07:00
|
|
|
|
2023-04-07 06:30:50 -07:00
|
|
|
SwapChainBase::SwapChainBase(DeviceBase* device,
|
|
|
|
Surface* surface,
|
|
|
|
const SwapChainDescriptor* descriptor)
|
|
|
|
: ApiObjectBase(device, kLabelNotImplemented),
|
|
|
|
mWidth(descriptor->width),
|
|
|
|
mHeight(descriptor->height),
|
|
|
|
mFormat(descriptor->format),
|
|
|
|
mUsage(descriptor->usage),
|
|
|
|
mPresentMode(descriptor->presentMode),
|
|
|
|
mSurface(surface) {
|
2022-09-15 14:06:51 -07:00
|
|
|
GetObjectTrackingList()->Track(this);
|
2022-05-01 07:40:55 -07:00
|
|
|
}
|
2021-12-01 10:54:40 -08:00
|
|
|
|
2023-04-07 06:30:50 -07:00
|
|
|
SwapChainBase::~SwapChainBase() {
|
2023-05-23 05:30:36 -07:00
|
|
|
if (mCurrentTexture != nullptr) {
|
|
|
|
ASSERT(mCurrentTexture->GetTextureState() == TextureBase::TextureState::Destroyed);
|
2023-04-07 06:30:50 -07:00
|
|
|
}
|
2017-07-19 15:41:17 -07:00
|
|
|
|
2023-04-07 06:30:50 -07:00
|
|
|
ASSERT(!mAttached);
|
|
|
|
}
|
2022-05-01 07:40:55 -07:00
|
|
|
|
2023-05-26 03:32:17 -07:00
|
|
|
SwapChainBase::SwapChainBase(DeviceBase* device,
|
|
|
|
const SwapChainDescriptor* descriptor,
|
|
|
|
ObjectBase::ErrorTag tag)
|
|
|
|
: ApiObjectBase(device, tag),
|
|
|
|
mWidth(descriptor->width),
|
|
|
|
mHeight(descriptor->height),
|
|
|
|
mFormat(descriptor->format),
|
|
|
|
mUsage(descriptor->usage),
|
|
|
|
mPresentMode(descriptor->presentMode) {}
|
2022-05-01 07:40:55 -07:00
|
|
|
|
|
|
|
// static
|
2023-05-26 03:32:17 -07:00
|
|
|
SwapChainBase* SwapChainBase::MakeError(DeviceBase* device, const SwapChainDescriptor* desc) {
|
|
|
|
return new ErrorSwapChain(device, desc);
|
2022-05-01 07:40:55 -07:00
|
|
|
}
|
|
|
|
|
2023-04-07 06:30:50 -07:00
|
|
|
void SwapChainBase::DestroyImpl() {}
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
ObjectType SwapChainBase::GetType() const {
|
|
|
|
return ObjectType::SwapChain;
|
|
|
|
}
|
2021-09-28 08:40:01 -07:00
|
|
|
|
2023-04-07 06:30:50 -07:00
|
|
|
void SwapChainBase::DetachFromSurface() {
|
2022-05-01 07:40:55 -07:00
|
|
|
if (mAttached) {
|
|
|
|
DetachFromSurfaceImpl();
|
|
|
|
mSurface = nullptr;
|
|
|
|
mAttached = false;
|
2020-01-23 09:20:38 -08:00
|
|
|
}
|
2022-05-01 07:40:55 -07:00
|
|
|
}
|
2020-01-23 09:20:38 -08:00
|
|
|
|
2023-04-07 06:30:50 -07:00
|
|
|
void SwapChainBase::SetIsAttached() {
|
2022-05-01 07:40:55 -07:00
|
|
|
mAttached = true;
|
|
|
|
}
|
|
|
|
|
2023-04-07 06:30:50 -07:00
|
|
|
void SwapChainBase::APIConfigure(wgpu::TextureFormat format,
|
|
|
|
wgpu::TextureUsage allowedUsage,
|
|
|
|
uint32_t width,
|
|
|
|
uint32_t height) {
|
2023-03-01 17:24:03 -08:00
|
|
|
GetDevice()->HandleError(
|
2022-08-30 06:39:47 -07:00
|
|
|
DAWN_VALIDATION_ERROR("Configure is invalid for surface-based swapchains."));
|
2022-05-01 07:40:55 -07:00
|
|
|
}
|
|
|
|
|
2023-05-26 03:32:17 -07:00
|
|
|
TextureBase* SwapChainBase::APIGetCurrentTexture() {
|
|
|
|
Ref<TextureBase> result;
|
|
|
|
if (GetDevice()->ConsumedError(GetCurrentTexture(), &result, "calling %s.GetCurrentTexture()",
|
|
|
|
this)) {
|
|
|
|
TextureDescriptor desc = GetSwapChainBaseTextureDescriptor(this);
|
|
|
|
TextureBase* errorTexture = TextureBase::MakeError(GetDevice(), &desc);
|
|
|
|
SetChildLabel(errorTexture);
|
|
|
|
return errorTexture;
|
|
|
|
}
|
|
|
|
return result.Detach();
|
|
|
|
}
|
|
|
|
|
2023-04-07 06:30:50 -07:00
|
|
|
TextureViewBase* SwapChainBase::APIGetCurrentTextureView() {
|
2022-05-01 07:40:55 -07:00
|
|
|
Ref<TextureViewBase> result;
|
|
|
|
if (GetDevice()->ConsumedError(GetCurrentTextureView(), &result,
|
|
|
|
"calling %s.GetCurrentTextureView()", this)) {
|
2023-05-26 03:32:17 -07:00
|
|
|
TextureViewBase* errorView = TextureViewBase::MakeError(GetDevice());
|
|
|
|
SetChildLabel(errorView);
|
|
|
|
return errorView;
|
2022-03-29 02:35:53 -07:00
|
|
|
}
|
2022-05-01 07:40:55 -07:00
|
|
|
return result.Detach();
|
|
|
|
}
|
2022-03-29 02:35:53 -07:00
|
|
|
|
2023-05-23 05:30:36 -07:00
|
|
|
ResultOrError<Ref<TextureBase>> SwapChainBase::GetCurrentTexture() {
|
|
|
|
DAWN_TRY(ValidateGetCurrentTexture());
|
2022-03-29 02:35:53 -07:00
|
|
|
|
2023-05-23 05:30:36 -07:00
|
|
|
if (mCurrentTexture != nullptr) {
|
|
|
|
// Calling GetCurrentTexture always returns a new reference.
|
|
|
|
return mCurrentTexture;
|
2020-01-23 09:20:38 -08:00
|
|
|
}
|
|
|
|
|
2023-05-23 05:30:36 -07:00
|
|
|
DAWN_TRY_ASSIGN(mCurrentTexture, GetCurrentTextureImpl());
|
2023-05-26 03:32:17 -07:00
|
|
|
SetChildLabel(mCurrentTexture.Get());
|
2023-05-23 05:30:36 -07:00
|
|
|
|
|
|
|
// Check that the return texture matches exactly what was given for this descriptor.
|
|
|
|
ASSERT(mCurrentTexture->GetFormat().format == mFormat);
|
|
|
|
ASSERT(IsSubset(mUsage, mCurrentTexture->GetUsage()));
|
|
|
|
ASSERT(mCurrentTexture->GetDimension() == wgpu::TextureDimension::e2D);
|
|
|
|
ASSERT(mCurrentTexture->GetWidth() == mWidth);
|
|
|
|
ASSERT(mCurrentTexture->GetHeight() == mHeight);
|
|
|
|
ASSERT(mCurrentTexture->GetNumMipLevels() == 1);
|
|
|
|
ASSERT(mCurrentTexture->GetArrayLayers() == 1);
|
|
|
|
|
|
|
|
return mCurrentTexture;
|
|
|
|
}
|
|
|
|
|
|
|
|
ResultOrError<Ref<TextureViewBase>> SwapChainBase::GetCurrentTextureView() {
|
|
|
|
Ref<TextureBase> currentTexture;
|
|
|
|
DAWN_TRY_ASSIGN(currentTexture, GetCurrentTexture());
|
|
|
|
return currentTexture->CreateView();
|
2022-05-01 07:40:55 -07:00
|
|
|
}
|
2020-01-23 09:20:38 -08:00
|
|
|
|
2023-04-07 06:30:50 -07:00
|
|
|
void SwapChainBase::APIPresent() {
|
2022-05-01 07:40:55 -07:00
|
|
|
if (GetDevice()->ConsumedError(ValidatePresent())) {
|
|
|
|
return;
|
2020-01-23 09:20:38 -08:00
|
|
|
}
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
if (GetDevice()->ConsumedError(PresentImpl())) {
|
|
|
|
return;
|
2020-01-23 09:20:38 -08:00
|
|
|
}
|
|
|
|
|
2023-05-23 05:30:36 -07:00
|
|
|
ASSERT(mCurrentTexture->GetTextureState() == TextureBase::TextureState::Destroyed);
|
|
|
|
mCurrentTexture = nullptr;
|
2022-05-01 07:40:55 -07:00
|
|
|
}
|
2020-01-23 09:20:38 -08:00
|
|
|
|
2023-04-07 06:30:50 -07:00
|
|
|
uint32_t SwapChainBase::GetWidth() const {
|
2022-05-01 07:40:55 -07:00
|
|
|
return mWidth;
|
|
|
|
}
|
2020-01-23 09:20:38 -08:00
|
|
|
|
2023-04-07 06:30:50 -07:00
|
|
|
uint32_t SwapChainBase::GetHeight() const {
|
2022-05-01 07:40:55 -07:00
|
|
|
return mHeight;
|
|
|
|
}
|
2020-03-20 10:07:20 -07:00
|
|
|
|
2023-04-07 06:30:50 -07:00
|
|
|
wgpu::TextureFormat SwapChainBase::GetFormat() const {
|
2022-05-01 07:40:55 -07:00
|
|
|
return mFormat;
|
|
|
|
}
|
2020-01-25 02:05:40 -08:00
|
|
|
|
2023-04-07 06:30:50 -07:00
|
|
|
wgpu::TextureUsage SwapChainBase::GetUsage() const {
|
2022-05-01 07:40:55 -07:00
|
|
|
return mUsage;
|
|
|
|
}
|
2020-01-25 02:05:40 -08:00
|
|
|
|
2023-04-07 06:30:50 -07:00
|
|
|
wgpu::PresentMode SwapChainBase::GetPresentMode() const {
|
2022-05-01 07:40:55 -07:00
|
|
|
return mPresentMode;
|
|
|
|
}
|
2020-01-25 02:05:40 -08:00
|
|
|
|
2023-04-07 06:30:50 -07:00
|
|
|
Surface* SwapChainBase::GetSurface() const {
|
2022-05-01 07:40:55 -07:00
|
|
|
return mSurface;
|
|
|
|
}
|
2020-01-25 02:05:40 -08:00
|
|
|
|
2023-04-07 06:30:50 -07:00
|
|
|
bool SwapChainBase::IsAttached() const {
|
2022-05-01 07:40:55 -07:00
|
|
|
return mAttached;
|
|
|
|
}
|
2020-01-25 02:05:40 -08:00
|
|
|
|
2023-04-07 06:30:50 -07:00
|
|
|
wgpu::BackendType SwapChainBase::GetBackendType() const {
|
2023-05-02 18:29:44 -07:00
|
|
|
return GetDevice()->GetPhysicalDevice()->GetBackendType();
|
2022-05-01 07:40:55 -07:00
|
|
|
}
|
2020-01-25 02:05:40 -08:00
|
|
|
|
2023-04-07 06:30:50 -07:00
|
|
|
MaybeError SwapChainBase::ValidatePresent() const {
|
2022-05-01 07:40:55 -07:00
|
|
|
DAWN_TRY(GetDevice()->ValidateIsAlive());
|
|
|
|
DAWN_TRY(GetDevice()->ValidateObject(this));
|
2020-01-25 02:05:40 -08:00
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
DAWN_INVALID_IF(!mAttached, "Cannot call Present called on detached %s.", this);
|
2020-01-25 02:05:40 -08:00
|
|
|
|
2023-05-23 05:30:36 -07:00
|
|
|
DAWN_INVALID_IF(mCurrentTexture == nullptr,
|
|
|
|
"GetCurrentTexture was not called on %s this frame prior to calling Present.",
|
|
|
|
this);
|
2020-01-25 02:05:40 -08:00
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2023-05-23 05:30:36 -07:00
|
|
|
MaybeError SwapChainBase::ValidateGetCurrentTexture() const {
|
2022-05-01 07:40:55 -07:00
|
|
|
DAWN_TRY(GetDevice()->ValidateIsAlive());
|
|
|
|
DAWN_TRY(GetDevice()->ValidateObject(this));
|
|
|
|
|
2023-05-23 05:30:36 -07:00
|
|
|
DAWN_INVALID_IF(!mAttached, "Cannot call GetCurrentTexture on detached %s.", this);
|
2022-05-01 07:40:55 -07:00
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
2020-01-23 09:20:38 -08:00
|
|
|
|
2023-05-26 03:32:17 -07:00
|
|
|
void SwapChainBase::SetChildLabel(ApiObjectBase* child) const {
|
|
|
|
child->SetLabel(absl::StrFormat("of %s", this));
|
|
|
|
}
|
|
|
|
|
2022-01-12 01:17:35 -08:00
|
|
|
} // namespace dawn::native
|