blob: 12f0fc3e6dc2a05fda150f888599f16a46ba4515 [file] [log] [blame]
/*
* Copyright 2022 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/gpu/graphite/dawn/DawnTexture.h"
#include "include/gpu/graphite/dawn/DawnTypes.h"
#include "include/private/gpu/graphite/DawnTypesPriv.h"
#include "src/core/SkMipmap.h"
#include "src/gpu/MutableTextureStateRef.h"
#include "src/gpu/graphite/Log.h"
#include "src/gpu/graphite/dawn/DawnCaps.h"
#include "src/gpu/graphite/dawn/DawnGraphiteUtilsPriv.h"
#include "src/gpu/graphite/dawn/DawnSharedContext.h"
namespace skgpu::graphite {
namespace {
const char* texture_info_to_label(const TextureInfo& info,
const DawnTextureSpec& dawnSpec) {
#ifdef SK_DEBUG
if (dawnSpec.fUsage & wgpu::TextureUsage::RenderAttachment) {
if (DawnFormatIsDepthOrStencil(dawnSpec.fFormat)) {
return "DepthStencil";
} else {
if (info.numSamples() > 1) {
if (dawnSpec.fUsage & wgpu::TextureUsage::TextureBinding) {
return "MSAA SampledTexture-ColorAttachment";
} else {
return "MSAA ColorAttachment";
}
} else {
if (dawnSpec.fUsage & wgpu::TextureUsage::TextureBinding) {
return "SampledTexture-ColorAttachment";
} else {
return "ColorAttachment";
}
}
}
} else {
SkASSERT(dawnSpec.fUsage & wgpu::TextureUsage::TextureBinding);
return "SampledTexture";
}
#else
return nullptr;
#endif
}
}
wgpu::Texture DawnTexture::MakeDawnTexture(const DawnSharedContext* sharedContext,
SkISize dimensions,
const TextureInfo& info) {
const Caps* caps = sharedContext->caps();
if (dimensions.width() > caps->maxTextureSize() ||
dimensions.height() > caps->maxTextureSize()) {
SKGPU_LOG_E("Texture creation failure: dimensions %d x %d too large.",
dimensions.width(), dimensions.height());
return {};
}
const DawnTextureSpec& dawnSpec = info.dawnTextureSpec();
if (dawnSpec.fUsage & wgpu::TextureUsage::TextureBinding && !caps->isTexturable(info)) {
return {};
}
if (dawnSpec.fUsage & wgpu::TextureUsage::RenderAttachment &&
!(caps->isRenderable(info) || DawnFormatIsDepthOrStencil(dawnSpec.fFormat))) {
return {};
}
if (dawnSpec.fUsage & wgpu::TextureUsage::StorageBinding && !caps->isStorage(info)) {
return {};
}
int numMipLevels = 1;
if (info.mipmapped() == Mipmapped::kYes) {
numMipLevels = SkMipmap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
}
wgpu::TextureDescriptor desc;
desc.label = texture_info_to_label(info, dawnSpec);
desc.usage = dawnSpec.fUsage;
desc.dimension = wgpu::TextureDimension::e2D;
desc.size.width = dimensions.width();
desc.size.height = dimensions.height();
desc.size.depthOrArrayLayers = 1;
desc.format = dawnSpec.fFormat;
desc.mipLevelCount = numMipLevels;
desc.sampleCount = info.numSamples();
desc.viewFormatCount = 0;
desc.viewFormats = nullptr;
auto texture = sharedContext->device().CreateTexture(&desc);
if (!texture) {
return {};
}
return texture;
}
DawnTexture::DawnTexture(const DawnSharedContext* sharedContext,
SkISize dimensions,
const TextureInfo& info,
wgpu::Texture texture,
wgpu::TextureView sampleTextureView,
wgpu::TextureView renderTextureView,
Ownership ownership,
skgpu::Budgeted budgeted)
: Texture(sharedContext, dimensions, info, /*mutableState=*/nullptr, ownership, budgeted)
, fTexture(std::move(texture))
, fSampleTextureView(std::move(sampleTextureView))
, fRenderTextureView(std::move(renderTextureView)) {}
std::pair<wgpu::TextureView, wgpu::TextureView> create_texture_views(
const wgpu::Texture& texture, const TextureInfo& info, const wgpu::TextureAspect aspect) {
if (aspect == wgpu::TextureAspect::All) {
wgpu::TextureView sampleTextureView = texture.CreateView();
wgpu::TextureView renderTextureView;
if (info.mipmapped() == Mipmapped::kYes) {
wgpu::TextureViewDescriptor renderViewDesc = {};
renderViewDesc.baseMipLevel = 0;
renderViewDesc.mipLevelCount = 1;
renderTextureView = texture.CreateView(&renderViewDesc);
} else {
renderTextureView = sampleTextureView;
}
return {sampleTextureView, renderTextureView};
}
SkASSERT(aspect == wgpu::TextureAspect::Plane0Only ||
aspect == wgpu::TextureAspect::Plane1Only ||
aspect == wgpu::TextureAspect::Plane2Only);
wgpu::TextureView planeTextureView;
wgpu::TextureViewDescriptor planeViewDesc = {};
planeViewDesc.aspect = aspect;
planeTextureView = texture.CreateView(&planeViewDesc);
return {planeTextureView, planeTextureView};
}
sk_sp<Texture> DawnTexture::Make(const DawnSharedContext* sharedContext,
SkISize dimensions,
const TextureInfo& info,
skgpu::Budgeted budgeted) {
auto texture = MakeDawnTexture(sharedContext, dimensions, info);
if (!texture) {
return {};
}
auto [sampleTextureView, renderTextureView] =
create_texture_views(texture, info, wgpu::TextureAspect::All);
return sk_sp<Texture>(new DawnTexture(sharedContext,
dimensions,
info,
std::move(texture),
std::move(sampleTextureView),
std::move(renderTextureView),
Ownership::kOwned,
budgeted));
}
sk_sp<Texture> DawnTexture::MakeWrapped(const DawnSharedContext* sharedContext,
SkISize dimensions,
const TextureInfo& info,
wgpu::Texture texture) {
if (!texture) {
SKGPU_LOG_E("No valid texture passed into MakeWrapped\n");
return {};
}
const wgpu::TextureAspect aspect = info.dawnTextureSpec().fAspect;
auto [sampleTextureView, renderTextureView] = create_texture_views(texture, info, aspect);
return sk_sp<Texture>(new DawnTexture(sharedContext,
dimensions,
info,
std::move(texture),
std::move(sampleTextureView),
std::move(renderTextureView),
Ownership::kWrapped,
skgpu::Budgeted::kNo));
}
void DawnTexture::freeGpuData() {
if (this->ownership() != Ownership::kWrapped && fTexture) {
// Destroy the texture even if it is still referenced by other BindGroup or views.
// Graphite should already guarantee that all command buffers using this texture (indirectly
// via BindGroup or views) are already completed.
fTexture.Destroy();
}
fTexture = nullptr;
fSampleTextureView = nullptr;
fRenderTextureView = nullptr;
}
} // namespace skgpu::graphite