mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-05-16 04:11:25 +00:00
Dawn currently allows sampling depth textures this way, but it is not in the WebGPU spec, and the behavior is not guaranteed with the Metal API. This commit also updates the stencil sampling tests to expect (s, s, s, s) or (s, 0, 0, 1). Bug: dawn:1021 Change-Id: I9210a2a3ff1655747a202a51f46f38faa35c85d4 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/59320 Commit-Queue: Austin Eng <enga@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org>
375 lines
15 KiB
C++
375 lines
15 KiB
C++
// Copyright 2017 The Dawn Authors
|
|
//
|
|
// 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.
|
|
|
|
#include "utils/WGPUHelpers.h"
|
|
|
|
#include "common/Constants.h"
|
|
#include "common/Log.h"
|
|
|
|
#include "spirv-tools/optimizer.hpp"
|
|
|
|
#include <cstring>
|
|
#include <iomanip>
|
|
#include <limits>
|
|
#include <mutex>
|
|
#include <sstream>
|
|
|
|
namespace utils {
|
|
wgpu::ShaderModule CreateShaderModuleFromASM(const wgpu::Device& device, const char* source) {
|
|
// Use SPIRV-Tools's C API to assemble the SPIR-V assembly text to binary. Because the types
|
|
// aren't RAII, we don't return directly on success and instead always go through the code
|
|
// path that destroys the SPIRV-Tools objects.
|
|
wgpu::ShaderModule result = nullptr;
|
|
|
|
spv_context context = spvContextCreate(SPV_ENV_UNIVERSAL_1_3);
|
|
ASSERT(context != nullptr);
|
|
|
|
spv_binary spirv = nullptr;
|
|
spv_diagnostic diagnostic = nullptr;
|
|
if (spvTextToBinary(context, source, strlen(source), &spirv, &diagnostic) == SPV_SUCCESS) {
|
|
ASSERT(spirv != nullptr);
|
|
ASSERT(spirv->wordCount <= std::numeric_limits<uint32_t>::max());
|
|
|
|
wgpu::ShaderModuleSPIRVDescriptor spirvDesc;
|
|
spirvDesc.codeSize = static_cast<uint32_t>(spirv->wordCount);
|
|
spirvDesc.code = spirv->code;
|
|
|
|
wgpu::ShaderModuleDescriptor descriptor;
|
|
descriptor.nextInChain = &spirvDesc;
|
|
result = device.CreateShaderModule(&descriptor);
|
|
} else {
|
|
ASSERT(diagnostic != nullptr);
|
|
dawn::WarningLog() << "CreateShaderModuleFromASM SPIRV assembly error:"
|
|
<< diagnostic->position.line + 1 << ":"
|
|
<< diagnostic->position.column + 1 << ": " << diagnostic->error;
|
|
}
|
|
|
|
spvDiagnosticDestroy(diagnostic);
|
|
spvBinaryDestroy(spirv);
|
|
spvContextDestroy(context);
|
|
|
|
return result;
|
|
}
|
|
|
|
wgpu::ShaderModule CreateShaderModule(const wgpu::Device& device, const char* source) {
|
|
wgpu::ShaderModuleWGSLDescriptor wgslDesc;
|
|
wgslDesc.source = source;
|
|
wgpu::ShaderModuleDescriptor descriptor;
|
|
descriptor.nextInChain = &wgslDesc;
|
|
return device.CreateShaderModule(&descriptor);
|
|
}
|
|
|
|
wgpu::Buffer CreateBufferFromData(const wgpu::Device& device,
|
|
const void* data,
|
|
uint64_t size,
|
|
wgpu::BufferUsage usage) {
|
|
wgpu::BufferDescriptor descriptor;
|
|
descriptor.size = size;
|
|
descriptor.usage = usage | wgpu::BufferUsage::CopyDst;
|
|
wgpu::Buffer buffer = device.CreateBuffer(&descriptor);
|
|
|
|
device.GetQueue().WriteBuffer(buffer, 0, data, size);
|
|
return buffer;
|
|
}
|
|
|
|
ComboRenderPassDescriptor::ComboRenderPassDescriptor(
|
|
std::initializer_list<wgpu::TextureView> colorAttachmentInfo,
|
|
wgpu::TextureView depthStencil) {
|
|
for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
|
|
cColorAttachments[i].loadOp = wgpu::LoadOp::Clear;
|
|
cColorAttachments[i].storeOp = wgpu::StoreOp::Store;
|
|
cColorAttachments[i].clearColor = {0.0f, 0.0f, 0.0f, 0.0f};
|
|
}
|
|
|
|
cDepthStencilAttachmentInfo.clearDepth = 1.0f;
|
|
cDepthStencilAttachmentInfo.clearStencil = 0;
|
|
cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Clear;
|
|
cDepthStencilAttachmentInfo.depthStoreOp = wgpu::StoreOp::Store;
|
|
cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Clear;
|
|
cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Store;
|
|
|
|
colorAttachmentCount = static_cast<uint32_t>(colorAttachmentInfo.size());
|
|
uint32_t colorAttachmentIndex = 0;
|
|
for (const wgpu::TextureView& colorAttachment : colorAttachmentInfo) {
|
|
if (colorAttachment.Get() != nullptr) {
|
|
cColorAttachments[colorAttachmentIndex].view = colorAttachment;
|
|
}
|
|
++colorAttachmentIndex;
|
|
}
|
|
colorAttachments = cColorAttachments.data();
|
|
|
|
if (depthStencil.Get() != nullptr) {
|
|
cDepthStencilAttachmentInfo.view = depthStencil;
|
|
depthStencilAttachment = &cDepthStencilAttachmentInfo;
|
|
} else {
|
|
depthStencilAttachment = nullptr;
|
|
}
|
|
}
|
|
|
|
ComboRenderPassDescriptor::ComboRenderPassDescriptor(const ComboRenderPassDescriptor& other) {
|
|
*this = other;
|
|
}
|
|
|
|
const ComboRenderPassDescriptor& ComboRenderPassDescriptor::operator=(
|
|
const ComboRenderPassDescriptor& otherRenderPass) {
|
|
cDepthStencilAttachmentInfo = otherRenderPass.cDepthStencilAttachmentInfo;
|
|
cColorAttachments = otherRenderPass.cColorAttachments;
|
|
colorAttachmentCount = otherRenderPass.colorAttachmentCount;
|
|
|
|
colorAttachments = cColorAttachments.data();
|
|
|
|
if (otherRenderPass.depthStencilAttachment != nullptr) {
|
|
// Assign desc.depthStencilAttachment to this->depthStencilAttachmentInfo;
|
|
depthStencilAttachment = &cDepthStencilAttachmentInfo;
|
|
} else {
|
|
depthStencilAttachment = nullptr;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
BasicRenderPass::BasicRenderPass()
|
|
: width(0),
|
|
height(0),
|
|
color(nullptr),
|
|
colorFormat(wgpu::TextureFormat::RGBA8Unorm),
|
|
renderPassInfo({}) {
|
|
}
|
|
|
|
BasicRenderPass::BasicRenderPass(uint32_t texWidth,
|
|
uint32_t texHeight,
|
|
wgpu::Texture colorAttachment,
|
|
wgpu::TextureFormat textureFormat)
|
|
: width(texWidth),
|
|
height(texHeight),
|
|
color(colorAttachment),
|
|
colorFormat(textureFormat),
|
|
renderPassInfo({colorAttachment.CreateView()}) {
|
|
}
|
|
|
|
BasicRenderPass CreateBasicRenderPass(const wgpu::Device& device,
|
|
uint32_t width,
|
|
uint32_t height,
|
|
wgpu::TextureFormat format) {
|
|
DAWN_ASSERT(width > 0 && height > 0);
|
|
|
|
wgpu::TextureDescriptor descriptor;
|
|
descriptor.dimension = wgpu::TextureDimension::e2D;
|
|
descriptor.size.width = width;
|
|
descriptor.size.height = height;
|
|
descriptor.size.depthOrArrayLayers = 1;
|
|
descriptor.sampleCount = 1;
|
|
descriptor.format = format;
|
|
descriptor.mipLevelCount = 1;
|
|
descriptor.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc;
|
|
wgpu::Texture color = device.CreateTexture(&descriptor);
|
|
|
|
return BasicRenderPass(width, height, color);
|
|
}
|
|
|
|
wgpu::ImageCopyBuffer CreateImageCopyBuffer(wgpu::Buffer buffer,
|
|
uint64_t offset,
|
|
uint32_t bytesPerRow,
|
|
uint32_t rowsPerImage) {
|
|
wgpu::ImageCopyBuffer imageCopyBuffer = {};
|
|
imageCopyBuffer.buffer = buffer;
|
|
imageCopyBuffer.layout = CreateTextureDataLayout(offset, bytesPerRow, rowsPerImage);
|
|
|
|
return imageCopyBuffer;
|
|
}
|
|
|
|
wgpu::ImageCopyTexture CreateImageCopyTexture(wgpu::Texture texture,
|
|
uint32_t mipLevel,
|
|
wgpu::Origin3D origin,
|
|
wgpu::TextureAspect aspect) {
|
|
wgpu::ImageCopyTexture imageCopyTexture;
|
|
imageCopyTexture.texture = texture;
|
|
imageCopyTexture.mipLevel = mipLevel;
|
|
imageCopyTexture.origin = origin;
|
|
imageCopyTexture.aspect = aspect;
|
|
|
|
return imageCopyTexture;
|
|
}
|
|
|
|
wgpu::TextureDataLayout CreateTextureDataLayout(uint64_t offset,
|
|
uint32_t bytesPerRow,
|
|
uint32_t rowsPerImage) {
|
|
wgpu::TextureDataLayout textureDataLayout;
|
|
textureDataLayout.offset = offset;
|
|
textureDataLayout.bytesPerRow = bytesPerRow;
|
|
textureDataLayout.rowsPerImage = rowsPerImage;
|
|
|
|
return textureDataLayout;
|
|
}
|
|
|
|
wgpu::PipelineLayout MakeBasicPipelineLayout(const wgpu::Device& device,
|
|
const wgpu::BindGroupLayout* bindGroupLayout) {
|
|
wgpu::PipelineLayoutDescriptor descriptor;
|
|
if (bindGroupLayout != nullptr) {
|
|
descriptor.bindGroupLayoutCount = 1;
|
|
descriptor.bindGroupLayouts = bindGroupLayout;
|
|
} else {
|
|
descriptor.bindGroupLayoutCount = 0;
|
|
descriptor.bindGroupLayouts = nullptr;
|
|
}
|
|
return device.CreatePipelineLayout(&descriptor);
|
|
}
|
|
|
|
wgpu::PipelineLayout MakePipelineLayout(const wgpu::Device& device,
|
|
std::vector<wgpu::BindGroupLayout> bgls) {
|
|
wgpu::PipelineLayoutDescriptor descriptor;
|
|
descriptor.bindGroupLayoutCount = uint32_t(bgls.size());
|
|
descriptor.bindGroupLayouts = bgls.data();
|
|
return device.CreatePipelineLayout(&descriptor);
|
|
}
|
|
|
|
wgpu::BindGroupLayout MakeBindGroupLayout(
|
|
const wgpu::Device& device,
|
|
std::initializer_list<BindingLayoutEntryInitializationHelper> entriesInitializer) {
|
|
std::vector<wgpu::BindGroupLayoutEntry> entries;
|
|
for (const BindingLayoutEntryInitializationHelper& entry : entriesInitializer) {
|
|
entries.push_back(entry);
|
|
}
|
|
|
|
wgpu::BindGroupLayoutDescriptor descriptor;
|
|
descriptor.entryCount = static_cast<uint32_t>(entries.size());
|
|
descriptor.entries = entries.data();
|
|
return device.CreateBindGroupLayout(&descriptor);
|
|
}
|
|
|
|
BindingLayoutEntryInitializationHelper::BindingLayoutEntryInitializationHelper(
|
|
uint32_t entryBinding,
|
|
wgpu::ShaderStage entryVisibility,
|
|
wgpu::BufferBindingType bufferType,
|
|
bool bufferHasDynamicOffset,
|
|
uint64_t bufferMinBindingSize) {
|
|
binding = entryBinding;
|
|
visibility = entryVisibility;
|
|
buffer.type = bufferType;
|
|
buffer.hasDynamicOffset = bufferHasDynamicOffset;
|
|
buffer.minBindingSize = bufferMinBindingSize;
|
|
}
|
|
|
|
BindingLayoutEntryInitializationHelper::BindingLayoutEntryInitializationHelper(
|
|
uint32_t entryBinding,
|
|
wgpu::ShaderStage entryVisibility,
|
|
wgpu::SamplerBindingType samplerType) {
|
|
binding = entryBinding;
|
|
visibility = entryVisibility;
|
|
sampler.type = samplerType;
|
|
}
|
|
|
|
BindingLayoutEntryInitializationHelper::BindingLayoutEntryInitializationHelper(
|
|
uint32_t entryBinding,
|
|
wgpu::ShaderStage entryVisibility,
|
|
wgpu::TextureSampleType textureSampleType,
|
|
wgpu::TextureViewDimension textureViewDimension,
|
|
bool textureMultisampled) {
|
|
binding = entryBinding;
|
|
visibility = entryVisibility;
|
|
texture.sampleType = textureSampleType;
|
|
texture.viewDimension = textureViewDimension;
|
|
texture.multisampled = textureMultisampled;
|
|
}
|
|
|
|
BindingLayoutEntryInitializationHelper::BindingLayoutEntryInitializationHelper(
|
|
uint32_t entryBinding,
|
|
wgpu::ShaderStage entryVisibility,
|
|
wgpu::StorageTextureAccess storageTextureAccess,
|
|
wgpu::TextureFormat format,
|
|
wgpu::TextureViewDimension textureViewDimension) {
|
|
binding = entryBinding;
|
|
visibility = entryVisibility;
|
|
storageTexture.access = storageTextureAccess;
|
|
storageTexture.format = format;
|
|
storageTexture.viewDimension = textureViewDimension;
|
|
}
|
|
|
|
// ExternalTextureBindingLayout never contains data, so just make one that can be reused instead
|
|
// of declaring a new one every time it's needed.
|
|
wgpu::ExternalTextureBindingLayout kExternalTextureBindingLayout = {};
|
|
|
|
BindingLayoutEntryInitializationHelper::BindingLayoutEntryInitializationHelper(
|
|
uint32_t entryBinding,
|
|
wgpu::ShaderStage entryVisibility,
|
|
wgpu::ExternalTextureBindingLayout* bindingLayout) {
|
|
binding = entryBinding;
|
|
visibility = entryVisibility;
|
|
nextInChain = bindingLayout;
|
|
}
|
|
|
|
BindingLayoutEntryInitializationHelper::BindingLayoutEntryInitializationHelper(
|
|
const wgpu::BindGroupLayoutEntry& entry)
|
|
: wgpu::BindGroupLayoutEntry(entry) {
|
|
}
|
|
|
|
BindingInitializationHelper::BindingInitializationHelper(uint32_t binding,
|
|
const wgpu::Sampler& sampler)
|
|
: binding(binding), sampler(sampler) {
|
|
}
|
|
|
|
BindingInitializationHelper::BindingInitializationHelper(uint32_t binding,
|
|
const wgpu::TextureView& textureView)
|
|
: binding(binding), textureView(textureView) {
|
|
}
|
|
|
|
BindingInitializationHelper::BindingInitializationHelper(
|
|
uint32_t binding,
|
|
const wgpu::ExternalTexture& externalTexture)
|
|
: binding(binding) {
|
|
externalTextureBindingEntry.externalTexture = externalTexture;
|
|
}
|
|
|
|
BindingInitializationHelper::BindingInitializationHelper(uint32_t binding,
|
|
const wgpu::Buffer& buffer,
|
|
uint64_t offset,
|
|
uint64_t size)
|
|
: binding(binding), buffer(buffer), offset(offset), size(size) {
|
|
}
|
|
|
|
wgpu::BindGroupEntry BindingInitializationHelper::GetAsBinding() const {
|
|
wgpu::BindGroupEntry result;
|
|
|
|
result.binding = binding;
|
|
result.sampler = sampler;
|
|
result.textureView = textureView;
|
|
result.buffer = buffer;
|
|
result.offset = offset;
|
|
result.size = size;
|
|
if (externalTextureBindingEntry.externalTexture != nullptr) {
|
|
result.nextInChain = &externalTextureBindingEntry;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
wgpu::BindGroup MakeBindGroup(
|
|
const wgpu::Device& device,
|
|
const wgpu::BindGroupLayout& layout,
|
|
std::initializer_list<BindingInitializationHelper> entriesInitializer) {
|
|
std::vector<wgpu::BindGroupEntry> entries;
|
|
for (const BindingInitializationHelper& helper : entriesInitializer) {
|
|
entries.push_back(helper.GetAsBinding());
|
|
}
|
|
|
|
wgpu::BindGroupDescriptor descriptor;
|
|
descriptor.layout = layout;
|
|
descriptor.entryCount = entries.size();
|
|
descriptor.entries = entries.data();
|
|
|
|
return device.CreateBindGroup(&descriptor);
|
|
}
|
|
|
|
} // namespace utils
|