blob: 383805dc21876c003740f609602e83ee8016cf72 [file]
/*
* 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/DawnGraphiteUtils.h"
#include "include/gpu/ShaderErrorHandler.h"
#include "include/gpu/graphite/Context.h"
#include "include/gpu/graphite/dawn/DawnBackendContext.h"
#include "src/gpu/graphite/ContextPriv.h"
#include "src/gpu/graphite/TextureFormat.h"
#include "src/gpu/graphite/dawn/DawnQueueManager.h"
#include "src/gpu/graphite/dawn/DawnSharedContext.h"
namespace skgpu::graphite {
namespace ContextFactory {
std::unique_ptr<Context> MakeDawn(const DawnBackendContext& backendContext,
const ContextOptions& options) {
sk_sp<SharedContext> sharedContext = DawnSharedContext::Make(backendContext, options);
if (!sharedContext) {
return nullptr;
}
auto queueManager =
std::make_unique<DawnQueueManager>(backendContext.fQueue, sharedContext.get());
if (!queueManager) {
return nullptr;
}
auto context = ContextCtorAccessor::MakeContext(std::move(sharedContext),
std::move(queueManager),
options);
SkASSERT(context);
return context;
}
} // namespace ContextFactory
SkTextureCompressionType DawnFormatToCompressionType(wgpu::TextureFormat format) {
switch (format) {
case wgpu::TextureFormat::ETC2RGB8Unorm: return SkTextureCompressionType::kETC2_RGB8_UNORM;
case wgpu::TextureFormat::BC1RGBAUnorm: return SkTextureCompressionType::kBC1_RGBA8_UNORM;
default: return SkTextureCompressionType::kNone;
}
}
bool DawnFormatIsDepthOrStencil(wgpu::TextureFormat format) {
switch (format) {
case wgpu::TextureFormat::Stencil8: [[fallthrough]];
case wgpu::TextureFormat::Depth16Unorm:
case wgpu::TextureFormat::Depth32Float:
case wgpu::TextureFormat::Depth24PlusStencil8:
case wgpu::TextureFormat::Depth32FloatStencil8:
return true;
default:
return false;
}
SkUNREACHABLE;
}
bool DawnFormatIsDepth(wgpu::TextureFormat format) {
switch (format) {
case wgpu::TextureFormat::Depth16Unorm: [[fallthrough]];
case wgpu::TextureFormat::Depth32Float:
case wgpu::TextureFormat::Depth24PlusStencil8:
case wgpu::TextureFormat::Depth32FloatStencil8:
return true;
default:
return false;
}
SkUNREACHABLE;
}
bool DawnFormatIsStencil(wgpu::TextureFormat format) {
switch (format) {
case wgpu::TextureFormat::Stencil8: [[fallthrough]];
case wgpu::TextureFormat::Depth24PlusStencil8:
case wgpu::TextureFormat::Depth32FloatStencil8:
return true;
default:
return false;
}
SkUNREACHABLE;
}
wgpu::TextureFormat DawnDepthStencilFlagsToFormat(SkEnumBitMask<DepthStencilFlags> mask) {
// TODO: Decide if we want to change this to always return a combined depth and stencil format
// to allow more sharing of depth stencil allocations.
if (mask == DepthStencilFlags::kDepth) {
// If needed for workarounds or performance, Depth32Float is also available but requires 2x
// the amount of memory.
return wgpu::TextureFormat::Depth16Unorm;
} else if (mask == DepthStencilFlags::kStencil) {
return wgpu::TextureFormat::Stencil8;
} else if (mask == DepthStencilFlags::kDepthStencil) {
return wgpu::TextureFormat::Depth24PlusStencil8;
}
SkASSERT(false);
return wgpu::TextureFormat::Undefined;
}
TextureFormat DawnFormatToTextureFormat(wgpu::TextureFormat format) {
switch (format) {
case wgpu::TextureFormat::R8Unorm: return TextureFormat::kR8;
case wgpu::TextureFormat::R16Float: return TextureFormat::kR16F;
case wgpu::TextureFormat::R32Float: return TextureFormat::kR32F;
case wgpu::TextureFormat::RG8Unorm: return TextureFormat::kRG8;
case wgpu::TextureFormat::RG16Float: return TextureFormat::kRG16F;
case wgpu::TextureFormat::RG32Float: return TextureFormat::kRG32F;
case wgpu::TextureFormat::RGBA8Unorm: return TextureFormat::kRGBA8;
case wgpu::TextureFormat::RGBA16Float: return TextureFormat::kRGBA16F;
case wgpu::TextureFormat::RGBA32Float: return TextureFormat::kRGBA32F;
case wgpu::TextureFormat::RGB10A2Unorm: return TextureFormat::kRGB10_A2;
case wgpu::TextureFormat::RGBA8UnormSrgb: return TextureFormat::kRGBA8_sRGB;
case wgpu::TextureFormat::BGRA8Unorm: return TextureFormat::kBGRA8;
case wgpu::TextureFormat::BGRA8UnormSrgb: return TextureFormat::kBGRA8_sRGB;
case wgpu::TextureFormat::ETC2RGB8Unorm: return TextureFormat::kRGB8_ETC2;
case wgpu::TextureFormat::ETC2RGB8UnormSrgb: return TextureFormat::kRGB8_ETC2_sRGB;
case wgpu::TextureFormat::BC1RGBAUnorm: return TextureFormat::kRGBA8_BC1;
case wgpu::TextureFormat::BC1RGBAUnormSrgb: return TextureFormat::kRGBA8_BC1_sRGB;
case wgpu::TextureFormat::Stencil8: return TextureFormat::kS8;
case wgpu::TextureFormat::Depth16Unorm: return TextureFormat::kD16;
case wgpu::TextureFormat::Depth32Float: return TextureFormat::kD32F;
case wgpu::TextureFormat::Depth24PlusStencil8: return TextureFormat::kD24_S8;
case wgpu::TextureFormat::Depth32FloatStencil8: return TextureFormat::kD32F_S8;
#if !defined(__EMSCRIPTEN__)
case wgpu::TextureFormat::R16Unorm: return TextureFormat::kR16;
case wgpu::TextureFormat::RG16Unorm: return TextureFormat::kRG16;
case wgpu::TextureFormat::RGBA16Unorm: return TextureFormat::kRGBA16;
case wgpu::TextureFormat::R8BG8Biplanar420Unorm: return TextureFormat::kYUV8_P2_420;
case wgpu::TextureFormat::R10X6BG10X6Biplanar420Unorm:
return TextureFormat::kYUV10x6_P2_420;
case wgpu::TextureFormat::External: return TextureFormat::kExternal;
#endif
default: return TextureFormat::kUnsupported;
}
}
static bool check_shader_module([[maybe_unused]] const DawnSharedContext* sharedContext,
wgpu::ShaderModule* module,
const char* shaderText,
ShaderErrorHandler* errorHandler) {
// Prior to emsdk 3.1.51 wgpu::ShaderModule::GetCompilationInfo is unimplemented.
#if defined(__EMSCRIPTEN__) && \
((__EMSCRIPTEN_major__ < 3 || \
(__EMSCRIPTEN_major__ == 3 && __EMSCRIPTEN_minor__ < 1) || \
(__EMSCRIPTEN_major__ == 3 && __EMSCRIPTEN_minor__ == 1 && __EMSCRIPTEN_tiny__ < 51)))
return true;
#else
struct Handler {
static void Fn(WGPUCompilationInfoRequestStatus status,
const WGPUCompilationInfo* info,
void* userdata) {
Handler* self = reinterpret_cast<Handler*>(userdata);
SkASSERT(status == WGPUCompilationInfoRequestStatus_Success);
// Walk the message list and check for hard errors.
self->fSuccess = true;
for (size_t index = 0; index < info->messageCount; ++index) {
const WGPUCompilationMessage& entry = info->messages[index];
if (entry.type == WGPUCompilationMessageType_Error) {
self->fSuccess = false;
break;
}
}
// If we found a hard error, report the compilation messages to the error handler.
if (!self->fSuccess) {
std::string errors;
for (size_t index = 0; index < info->messageCount; ++index) {
const WGPUCompilationMessage& entry = info->messages[index];
#if defined(WGPU_BREAKING_CHANGE_STRING_VIEW_OUTPUT_STRUCTS)
std::string messageString(entry.message.data, entry.message.length);
#else // defined(WGPU_BREAKING_CHANGE_STRING_VIEW_OUTPUT_STRUCTS)
std::string messageString(entry.message);
#endif // defined(WGPU_BREAKING_CHANGE_STRING_VIEW_OUTPUT_STRUCTS)
errors += "line " + std::to_string(entry.lineNum) + ':' +
std::to_string(entry.linePos) + ' ' + messageString + '\n';
}
self->fErrorHandler->compileError(
self->fShaderText, errors.c_str(), /*shaderWasCached=*/false);
}
}
const char* fShaderText;
ShaderErrorHandler* fErrorHandler;
bool fSuccess = false;
};
Handler handler;
handler.fShaderText = shaderText;
handler.fErrorHandler = errorHandler;
#if defined(__EMSCRIPTEN__)
// Deprecated function.
module->GetCompilationInfo(&Handler::Fn, &handler);
#else
// New API.
wgpu::FutureWaitInfo waitInfo{};
waitInfo.future = module->GetCompilationInfo(
wgpu::CallbackMode::WaitAnyOnly,
[handlerPtr = &handler](wgpu::CompilationInfoRequestStatus status,
const wgpu::CompilationInfo* info) {
Handler::Fn(static_cast<WGPUCompilationInfoRequestStatus>(status),
reinterpret_cast<const WGPUCompilationInfo*>(info),
handlerPtr);
});
const auto& instance = static_cast<const DawnSharedContext*>(sharedContext)
->device()
.GetAdapter()
.GetInstance();
[[maybe_unused]] auto status =
instance.WaitAny(1, &waitInfo, /*timeoutNS=*/std::numeric_limits<uint64_t>::max());
SkASSERT(status == wgpu::WaitStatus::Success);
#endif // defined(__EMSCRIPTEN__)
return handler.fSuccess;
#endif
}
bool DawnCompileWGSLShaderModule(const DawnSharedContext* sharedContext,
const char* label,
const std::string& wgsl,
wgpu::ShaderModule* module,
ShaderErrorHandler* errorHandler) {
#if defined(__EMSCRIPTEN__)
wgpu::ShaderModuleWGSLDescriptor wgslDesc;
#else
wgpu::ShaderSourceWGSL wgslDesc;
#endif
wgslDesc.code = wgsl.c_str();
wgpu::ShaderModuleDescriptor desc;
desc.nextInChain = &wgslDesc;
if (sharedContext->caps()->setBackendLabels()) {
desc.label = label;
}
*module = sharedContext->device().CreateShaderModule(&desc);
return check_shader_module(sharedContext, module, wgsl.c_str(), errorHandler);
}
#if !defined(__EMSCRIPTEN__)
namespace {
static constexpr int kUsesExternalFormatBits = 1;
static constexpr int kYcbcrModelBits = 3;
static constexpr int kYcbcrRangeBits = 1;
static constexpr int kXChromaOffsetBits = 1;
static constexpr int kYChromaOffsetBits = 1;
// wgpu::FilterMode contains Undefined/Nearest/Linear entries (Linear is 2).
static constexpr int kChromaFilterBits = 2;
static constexpr int kForceExplicitReconBits = 1;
static constexpr int kComponentBits = 3;
static constexpr int kUsesExternalFormatShift = 0;
static constexpr int kYcbcrModelShift = kUsesExternalFormatShift + kUsesExternalFormatBits;
static constexpr int kYcbcrRangeShift = kYcbcrModelShift + kYcbcrModelBits;
static constexpr int kXChromaOffsetShift = kYcbcrRangeShift + kYcbcrRangeBits;
static constexpr int kYChromaOffsetShift = kXChromaOffsetShift + kXChromaOffsetBits;
static constexpr int kChromaFilterShift = kYChromaOffsetShift + kYChromaOffsetBits;
static constexpr int kForceExplicitReconShift = kChromaFilterShift + kChromaFilterBits;
static constexpr int kComponentRShift = kForceExplicitReconShift + kForceExplicitReconBits;
static constexpr int kComponentGShift = kComponentRShift + kComponentBits;
static constexpr int kComponentBShift = kComponentGShift + kComponentBits;
static constexpr int kComponentAShift = kComponentBShift + kComponentBits;
static constexpr uint32_t kUseExternalFormatMask =
((1 << kUsesExternalFormatBits) - 1) << kUsesExternalFormatShift;
static constexpr uint32_t kYcbcrModelMask =
((1 << kYcbcrModelBits) - 1) << kYcbcrModelShift;
static constexpr uint32_t kYcbcrRangeMask =
((1 << kYcbcrRangeBits) - 1) << kYcbcrRangeShift;
static constexpr uint32_t kXChromaOffsetMask =
((1 << kXChromaOffsetBits) - 1) << kXChromaOffsetShift;
static constexpr uint32_t kYChromaOffsetMask =
((1 << kYChromaOffsetBits) - 1) << kYChromaOffsetShift;
static constexpr uint32_t kChromaFilterMask =
((1 << kChromaFilterBits) - 1) << kChromaFilterShift;
static constexpr uint32_t kForceExplicitReconMask =
((1 << kForceExplicitReconBits) - 1) << kForceExplicitReconShift;
static constexpr uint32_t kComponentRMask = ((1 << kComponentBits) - 1) << kComponentRShift;
static constexpr uint32_t kComponentBMask = ((1 << kComponentBits) - 1) << kComponentBShift;
static constexpr uint32_t kComponentGMask = ((1 << kComponentBits) - 1) << kComponentGShift;
static constexpr uint32_t kComponentAMask = ((1 << kComponentBits) - 1) << kComponentAShift;
} // anonymous namespace
bool DawnDescriptorsAreEquivalent(const wgpu::YCbCrVkDescriptor& desc1,
const wgpu::YCbCrVkDescriptor& desc2) {
return desc1.vkFormat == desc2.vkFormat &&
desc1.vkYCbCrModel == desc2.vkYCbCrModel &&
desc1.vkYCbCrRange == desc2.vkYCbCrRange &&
desc1.vkComponentSwizzleRed == desc2.vkComponentSwizzleRed &&
desc1.vkComponentSwizzleGreen == desc2.vkComponentSwizzleGreen &&
desc1.vkComponentSwizzleBlue == desc2.vkComponentSwizzleBlue &&
desc1.vkComponentSwizzleAlpha == desc2.vkComponentSwizzleAlpha &&
desc1.vkXChromaOffset == desc2.vkXChromaOffset &&
desc1.vkYChromaOffset == desc2.vkYChromaOffset &&
desc1.vkChromaFilter == desc2.vkChromaFilter &&
desc1.forceExplicitReconstruction == desc2.forceExplicitReconstruction &&
desc1.externalFormat == desc2.externalFormat;
}
bool DawnDescriptorIsValid(const wgpu::YCbCrVkDescriptor& desc) {
static const wgpu::YCbCrVkDescriptor kDefaultYcbcrDescriptor = {};
return !DawnDescriptorsAreEquivalent(desc, kDefaultYcbcrDescriptor);
}
bool DawnDescriptorUsesExternalFormat(const wgpu::YCbCrVkDescriptor& desc) {
SkASSERT(desc.externalFormat != 0 || desc.vkFormat != 0);
return desc.externalFormat != 0;
}
ImmutableSamplerInfo DawnDescriptorToImmutableSamplerInfo(const wgpu::YCbCrVkDescriptor& desc) {
static_assert(kComponentAShift + kComponentBits <= 32);
SkASSERT(desc.vkYCbCrModel < (1u << kYcbcrModelBits ));
SkASSERT(desc.vkYCbCrRange < (1u << kYcbcrRangeBits ));
SkASSERT(desc.vkXChromaOffset < (1u << kXChromaOffsetBits ));
SkASSERT(desc.vkYChromaOffset < (1u << kYChromaOffsetBits ));
SkASSERT(static_cast<uint32_t>(desc.vkChromaFilter) < (1u << kChromaFilterBits ));
SkASSERT(desc.vkComponentSwizzleRed < (1u << kComponentBits ));
SkASSERT(desc.vkComponentSwizzleGreen < (1u << kComponentBits ));
SkASSERT(desc.vkComponentSwizzleBlue < (1u << kComponentBits ));
SkASSERT(desc.vkComponentSwizzleAlpha < (1u << kComponentBits ));
SkASSERT(static_cast<uint32_t>(desc.forceExplicitReconstruction)
< (1u << kForceExplicitReconBits));
const bool usesExternalFormat = DawnDescriptorUsesExternalFormat(desc);
ImmutableSamplerInfo info;
info.fNonFormatYcbcrConversionInfo =
(((uint32_t)(usesExternalFormat ) << kUsesExternalFormatShift) |
((uint32_t)(desc.vkYCbCrModel ) << kYcbcrModelShift ) |
((uint32_t)(desc.vkYCbCrRange ) << kYcbcrRangeShift ) |
((uint32_t)(desc.vkXChromaOffset ) << kXChromaOffsetShift ) |
((uint32_t)(desc.vkYChromaOffset ) << kYChromaOffsetShift ) |
((uint32_t)(desc.vkChromaFilter ) << kChromaFilterShift ) |
((uint32_t)(desc.forceExplicitReconstruction ) << kForceExplicitReconShift) |
((uint32_t)(desc.vkComponentSwizzleRed ) << kComponentRShift ) |
((uint32_t)(desc.vkComponentSwizzleGreen ) << kComponentGShift ) |
((uint32_t)(desc.vkComponentSwizzleBlue ) << kComponentBShift ) |
((uint32_t)(desc.vkComponentSwizzleAlpha ) << kComponentAShift ));
info.fFormat = usesExternalFormat ? desc.externalFormat : desc.vkFormat;
return info;
}
wgpu::YCbCrVkDescriptor DawnDescriptorFromImmutableSamplerInfo(ImmutableSamplerInfo info) {
const uint32_t nonFormatInfo = info.fNonFormatYcbcrConversionInfo;
wgpu::YCbCrVkDescriptor desc;
const bool usesExternalFormat =
(nonFormatInfo >> kUsesExternalFormatShift) & kUseExternalFormatMask;
if (usesExternalFormat) {
desc.vkFormat = 0;
desc.externalFormat = info.fFormat;
} else {
desc.vkFormat = (uint32_t) info.fFormat;
desc.externalFormat = 0;
}
desc.vkYCbCrModel = (nonFormatInfo & kYcbcrModelMask) >> kYcbcrModelShift;
desc.vkYCbCrRange = (nonFormatInfo & kYcbcrRangeMask) >> kYcbcrRangeShift;
desc.vkComponentSwizzleRed = (nonFormatInfo & kComponentRMask) >> kComponentRShift;
desc.vkComponentSwizzleGreen = (nonFormatInfo & kComponentGMask) >> kComponentGShift;
desc.vkComponentSwizzleBlue = (nonFormatInfo & kComponentBMask) >> kComponentBShift;
desc.vkComponentSwizzleAlpha = (nonFormatInfo & kComponentAMask) >> kComponentAShift;
desc.vkXChromaOffset = (nonFormatInfo & kXChromaOffsetMask) >> kXChromaOffsetShift;
desc.vkYChromaOffset = (nonFormatInfo & kYChromaOffsetMask) >> kYChromaOffsetShift;
desc.vkChromaFilter = static_cast<wgpu::FilterMode>(
(nonFormatInfo & kChromaFilterMask) >> kChromaFilterShift);
desc.forceExplicitReconstruction =
(nonFormatInfo & kForceExplicitReconMask) >> kForceExplicitReconShift;
return desc;
}
#endif // !defined(__EMSCRIPTEN__)
} // namespace skgpu::graphite