D3D12: Apply big integer clear color values with draw
This patch implements the use of big integer values (>2^24 or <-2^24) as the clear values of a render pass with an internal draw call as D3D12 API only supports using float numbers as clear values. Bug: dawn:537 Test: dawn_end2end_tests Change-Id: Id0a7835d611f598fb77950915f69919f804a8702 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/98104 Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: Jiawei Shao <jiawei.shao@intel.com> Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
3f49e298e0
commit
7267d99251
|
@ -0,0 +1,396 @@
|
|||
// Copyright 2022 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 "dawn/native/ApplyClearColorValueWithDrawHelper.h"
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "dawn/native/BindGroup.h"
|
||||
#include "dawn/native/BindGroupLayout.h"
|
||||
#include "dawn/native/Device.h"
|
||||
#include "dawn/native/InternalPipelineStore.h"
|
||||
#include "dawn/native/ObjectContentHasher.h"
|
||||
#include "dawn/native/RenderPassEncoder.h"
|
||||
#include "dawn/native/RenderPipeline.h"
|
||||
#include "dawn/native/utils/WGPUHelpers.h"
|
||||
|
||||
namespace dawn::native {
|
||||
|
||||
namespace {
|
||||
|
||||
// General helper functions and data structures for applying clear values with draw
|
||||
static const char kVSSource[] = R"(
|
||||
@vertex
|
||||
fn main(@builtin(vertex_index) VertexIndex : u32) -> @builtin(position) vec4<f32> {
|
||||
var pos = array<vec2<f32>, 6>(
|
||||
vec2<f32>( 0.0, -1.0),
|
||||
vec2<f32>( 1.0, -1.0),
|
||||
vec2<f32>( 0.0, 1.0),
|
||||
vec2<f32>( 0.0, 1.0),
|
||||
vec2<f32>( 1.0, -1.0),
|
||||
vec2<f32>( 1.0, 1.0));
|
||||
return vec4<f32>(pos[VertexIndex], 0.0, 1.0);
|
||||
})";
|
||||
|
||||
const char* GetTextureComponentTypeString(DeviceBase* device, wgpu::TextureFormat format) {
|
||||
ASSERT(format != wgpu::TextureFormat::Undefined);
|
||||
|
||||
const Format& formatInfo = device->GetValidInternalFormat(format);
|
||||
switch (formatInfo.GetAspectInfo(Aspect::Color).baseType) {
|
||||
case wgpu::TextureComponentType::Sint:
|
||||
return "i32";
|
||||
case wgpu::TextureComponentType::Uint:
|
||||
return "u32";
|
||||
case wgpu::TextureComponentType::Float:
|
||||
case wgpu::TextureComponentType::DepthComparison:
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// Construct the fragment shader to apply the input color values to the corresponding color
|
||||
// attachments of KeyOfApplyClearColorValueWithDrawPipelines.
|
||||
std::string ConstructFragmentShader(DeviceBase* device,
|
||||
const KeyOfApplyClearColorValueWithDrawPipelines& key) {
|
||||
std::ostringstream outputColorDeclarationStream;
|
||||
std::ostringstream clearValueUniformBufferDeclarationStream;
|
||||
std::ostringstream assignOutputColorStream;
|
||||
|
||||
outputColorDeclarationStream << "struct OutputColor {" << std::endl;
|
||||
clearValueUniformBufferDeclarationStream << "struct ClearColors {" << std::endl;
|
||||
|
||||
// Only generate the assignments we need.
|
||||
for (uint32_t i : IterateBitSet(key.colorTargetsToApplyClearColorValue)) {
|
||||
wgpu::TextureFormat currentFormat = key.colorTargetFormats[i];
|
||||
ASSERT(currentFormat != wgpu::TextureFormat::Undefined);
|
||||
|
||||
const char* type = GetTextureComponentTypeString(device, currentFormat);
|
||||
|
||||
outputColorDeclarationStream << "@location(" << i << ") output" << i << " : vec4<" << type
|
||||
<< ">," << std::endl;
|
||||
clearValueUniformBufferDeclarationStream << "color" << i << " : vec4<" << type << ">,"
|
||||
<< std::endl;
|
||||
assignOutputColorStream << "outputColor.output" << i << " = clearColors.color" << i << ";"
|
||||
<< std::endl;
|
||||
}
|
||||
outputColorDeclarationStream << "}" << std::endl;
|
||||
clearValueUniformBufferDeclarationStream << "}" << std::endl;
|
||||
|
||||
std::ostringstream fragmentShaderStream;
|
||||
fragmentShaderStream << outputColorDeclarationStream.str()
|
||||
<< clearValueUniformBufferDeclarationStream.str() << R"(
|
||||
@group(0) @binding(0) var<uniform> clearColors : ClearColors;
|
||||
|
||||
@fragment
|
||||
fn main() -> OutputColor {
|
||||
var outputColor : OutputColor;
|
||||
)" << assignOutputColorStream.str()
|
||||
<< R"(
|
||||
return outputColor;
|
||||
})";
|
||||
|
||||
return fragmentShaderStream.str();
|
||||
}
|
||||
|
||||
RenderPipelineBase* GetCachedPipeline(InternalPipelineStore* store,
|
||||
const KeyOfApplyClearColorValueWithDrawPipelines& key) {
|
||||
auto iter = store->applyClearColorValueWithDrawPipelines.find(key);
|
||||
if (iter != store->applyClearColorValueWithDrawPipelines.end()) {
|
||||
return iter->second.Get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ResultOrError<RenderPipelineBase*> GetOrCreateApplyClearValueWithDrawPipeline(
|
||||
DeviceBase* device,
|
||||
const KeyOfApplyClearColorValueWithDrawPipelines& key) {
|
||||
InternalPipelineStore* store = device->GetInternalPipelineStore();
|
||||
RenderPipelineBase* cachedPipeline = GetCachedPipeline(store, key);
|
||||
if (cachedPipeline != nullptr) {
|
||||
return cachedPipeline;
|
||||
}
|
||||
|
||||
// Prepare the vertex stage
|
||||
Ref<ShaderModuleBase> vertexModule;
|
||||
DAWN_TRY_ASSIGN(vertexModule, utils::CreateShaderModule(device, kVSSource));
|
||||
VertexState vertex = {};
|
||||
vertex.module = vertexModule.Get();
|
||||
vertex.entryPoint = "main";
|
||||
|
||||
// Prepare the fragment stage
|
||||
std::string fragmentShader = ConstructFragmentShader(device, key);
|
||||
Ref<ShaderModuleBase> fragmentModule;
|
||||
DAWN_TRY_ASSIGN(fragmentModule, utils::CreateShaderModule(device, fragmentShader.c_str()));
|
||||
FragmentState fragment = {};
|
||||
fragment.module = fragmentModule.Get();
|
||||
fragment.entryPoint = "main";
|
||||
|
||||
// Prepare the color states
|
||||
std::array<ColorTargetState, kMaxColorAttachments> colorTargets = {};
|
||||
for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
|
||||
colorTargets[i].format = key.colorTargetFormats[i];
|
||||
// We shouldn't change the color targets that are not involved in.
|
||||
if (!key.colorTargetsToApplyClearColorValue[i]) {
|
||||
colorTargets[i].writeMask = wgpu::ColorWriteMask::None;
|
||||
}
|
||||
}
|
||||
|
||||
// Create RenderPipeline
|
||||
RenderPipelineDescriptor renderPipelineDesc = {};
|
||||
|
||||
renderPipelineDesc.vertex = vertex;
|
||||
renderPipelineDesc.fragment = &fragment;
|
||||
renderPipelineDesc.primitive.topology = wgpu::PrimitiveTopology::TriangleList;
|
||||
fragment.targetCount = key.colorAttachmentCount;
|
||||
fragment.targets = colorTargets.data();
|
||||
|
||||
Ref<RenderPipelineBase> pipeline;
|
||||
DAWN_TRY_ASSIGN(pipeline, device->CreateRenderPipeline(&renderPipelineDesc));
|
||||
store->applyClearColorValueWithDrawPipelines.insert({key, std::move(pipeline)});
|
||||
|
||||
return GetCachedPipeline(store, key);
|
||||
}
|
||||
|
||||
Color GetClearColorValue(const RenderPassColorAttachment& attachment) {
|
||||
return HasDeprecatedColor(attachment) ? attachment.clearColor : attachment.clearValue;
|
||||
}
|
||||
|
||||
ResultOrError<Ref<BufferBase>> CreateUniformBufferWithClearValues(
|
||||
DeviceBase* device,
|
||||
const RenderPassDescriptor* renderPassDescriptor,
|
||||
const KeyOfApplyClearColorValueWithDrawPipelines& key) {
|
||||
std::array<uint8_t, sizeof(uint32_t)* 4 * kMaxColorAttachments> clearValues = {};
|
||||
uint32_t offset = 0;
|
||||
for (uint32_t i : IterateBitSet(key.colorTargetsToApplyClearColorValue)) {
|
||||
const Format& format = renderPassDescriptor->colorAttachments[i].view->GetFormat();
|
||||
wgpu::TextureComponentType baseType = format.GetAspectInfo(Aspect::Color).baseType;
|
||||
|
||||
Color initialClearValue = GetClearColorValue(renderPassDescriptor->colorAttachments[i]);
|
||||
Color clearValue = ClampClearColorValueToLegalRange(initialClearValue, format);
|
||||
switch (baseType) {
|
||||
case wgpu::TextureComponentType::Uint: {
|
||||
uint32_t* clearValuePtr = reinterpret_cast<uint32_t*>(clearValues.data() + offset);
|
||||
clearValuePtr[0] = static_cast<uint32_t>(clearValue.r);
|
||||
clearValuePtr[1] = static_cast<uint32_t>(clearValue.g);
|
||||
clearValuePtr[2] = static_cast<uint32_t>(clearValue.b);
|
||||
clearValuePtr[3] = static_cast<uint32_t>(clearValue.a);
|
||||
break;
|
||||
}
|
||||
case wgpu::TextureComponentType::Sint: {
|
||||
int32_t* clearValuePtr = reinterpret_cast<int32_t*>(clearValues.data() + offset);
|
||||
clearValuePtr[0] = static_cast<int32_t>(clearValue.r);
|
||||
clearValuePtr[1] = static_cast<int32_t>(clearValue.g);
|
||||
clearValuePtr[2] = static_cast<int32_t>(clearValue.b);
|
||||
clearValuePtr[3] = static_cast<int32_t>(clearValue.a);
|
||||
break;
|
||||
}
|
||||
case wgpu::TextureComponentType::Float: {
|
||||
float* clearValuePtr = reinterpret_cast<float*>(clearValues.data() + offset);
|
||||
clearValuePtr[0] = static_cast<float>(clearValue.r);
|
||||
clearValuePtr[1] = static_cast<float>(clearValue.g);
|
||||
clearValuePtr[2] = static_cast<float>(clearValue.b);
|
||||
clearValuePtr[3] = static_cast<float>(clearValue.a);
|
||||
break;
|
||||
}
|
||||
|
||||
case wgpu::TextureComponentType::DepthComparison:
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
offset += sizeof(uint32_t) * 4;
|
||||
}
|
||||
|
||||
ASSERT(offset > 0);
|
||||
|
||||
Ref<BufferBase> outputBuffer;
|
||||
DAWN_TRY_ASSIGN(
|
||||
outputBuffer,
|
||||
utils::CreateBufferFromData(device, wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::Uniform,
|
||||
clearValues.data(), offset));
|
||||
|
||||
return std::move(outputBuffer);
|
||||
}
|
||||
|
||||
// Helper functions for applying big integer clear values with draw
|
||||
bool ShouldApplyClearBigIntegerColorValueWithDraw(
|
||||
const RenderPassColorAttachment& colorAttachmentInfo) {
|
||||
if (colorAttachmentInfo.view == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (colorAttachmentInfo.loadOp != wgpu::LoadOp::Clear) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We should only apply this workaround on 32-bit signed and unsigned integer formats.
|
||||
const Format& format = colorAttachmentInfo.view->GetFormat();
|
||||
switch (format.format) {
|
||||
case wgpu::TextureFormat::R32Sint:
|
||||
case wgpu::TextureFormat::RG32Sint:
|
||||
case wgpu::TextureFormat::RGBA32Sint:
|
||||
case wgpu::TextureFormat::R32Uint:
|
||||
case wgpu::TextureFormat::RG32Uint:
|
||||
case wgpu::TextureFormat::RGBA32Uint:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO(dawn:537): only check the color channels that are available in the current color format.
|
||||
Color clearValue = GetClearColorValue(colorAttachmentInfo);
|
||||
switch (format.GetAspectInfo(Aspect::Color).baseType) {
|
||||
case wgpu::TextureComponentType::Uint: {
|
||||
constexpr double kMaxUintRepresentableInFloat = 1 << std::numeric_limits<float>::digits;
|
||||
if (clearValue.r <= kMaxUintRepresentableInFloat &&
|
||||
clearValue.g <= kMaxUintRepresentableInFloat &&
|
||||
clearValue.b <= kMaxUintRepresentableInFloat &&
|
||||
clearValue.a <= kMaxUintRepresentableInFloat) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case wgpu::TextureComponentType::Sint: {
|
||||
constexpr double kMaxSintRepresentableInFloat = 1 << std::numeric_limits<float>::digits;
|
||||
constexpr double kMinSintRepresentableInFloat = -kMaxSintRepresentableInFloat;
|
||||
if (clearValue.r <= kMaxSintRepresentableInFloat &&
|
||||
clearValue.r >= kMinSintRepresentableInFloat &&
|
||||
clearValue.g <= kMaxSintRepresentableInFloat &&
|
||||
clearValue.g >= kMinSintRepresentableInFloat &&
|
||||
clearValue.b <= kMaxSintRepresentableInFloat &&
|
||||
clearValue.b >= kMinSintRepresentableInFloat &&
|
||||
clearValue.a <= kMaxSintRepresentableInFloat &&
|
||||
clearValue.a >= kMinSintRepresentableInFloat) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case wgpu::TextureComponentType::Float:
|
||||
case wgpu::TextureComponentType::DepthComparison:
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
KeyOfApplyClearColorValueWithDrawPipelines GetKeyOfApplyClearColorValueWithDrawPipelines(
|
||||
const RenderPassDescriptor* renderPassDescriptor) {
|
||||
KeyOfApplyClearColorValueWithDrawPipelines key;
|
||||
key.colorAttachmentCount = renderPassDescriptor->colorAttachmentCount;
|
||||
|
||||
key.colorTargetFormats.fill(wgpu::TextureFormat::Undefined);
|
||||
for (uint32_t i = 0; i < renderPassDescriptor->colorAttachmentCount; ++i) {
|
||||
if (renderPassDescriptor->colorAttachments[i].view != nullptr) {
|
||||
key.colorTargetFormats[i] =
|
||||
renderPassDescriptor->colorAttachments[i].view->GetFormat().format;
|
||||
}
|
||||
|
||||
if (ShouldApplyClearBigIntegerColorValueWithDraw(
|
||||
renderPassDescriptor->colorAttachments[i])) {
|
||||
key.colorTargetsToApplyClearColorValue.set(i);
|
||||
}
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
size_t KeyOfApplyClearColorValueWithDrawPipelinesHashFunc::operator()(
|
||||
KeyOfApplyClearColorValueWithDrawPipelines key) const {
|
||||
size_t hash = 0;
|
||||
|
||||
HashCombine(&hash, key.colorAttachmentCount);
|
||||
|
||||
HashCombine(&hash, key.colorTargetsToApplyClearColorValue);
|
||||
|
||||
for (wgpu::TextureFormat format : key.colorTargetFormats) {
|
||||
HashCombine(&hash, format);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
bool KeyOfApplyClearColorValueWithDrawPipelinesEqualityFunc::operator()(
|
||||
KeyOfApplyClearColorValueWithDrawPipelines key1,
|
||||
KeyOfApplyClearColorValueWithDrawPipelines key2) const {
|
||||
if (key1.colorAttachmentCount != key2.colorAttachmentCount) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (key1.colorTargetsToApplyClearColorValue != key2.colorTargetsToApplyClearColorValue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
|
||||
if (key1.colorTargetFormats[i] != key2.colorTargetFormats[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ShouldApplyClearBigIntegerColorValueWithDraw(
|
||||
const DeviceBase* device,
|
||||
const RenderPassDescriptor* renderPassDescriptor) {
|
||||
if (!device->IsToggleEnabled(Toggle::ApplyClearBigIntegerColorValueWithDraw)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < renderPassDescriptor->colorAttachmentCount; ++i) {
|
||||
if (ShouldApplyClearBigIntegerColorValueWithDraw(
|
||||
renderPassDescriptor->colorAttachments[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
MaybeError ApplyClearBigIntegerColorValueWithDraw(
|
||||
RenderPassEncoder* renderPassEncoder,
|
||||
const RenderPassDescriptor* renderPassDescriptor) {
|
||||
DeviceBase* device = renderPassEncoder->GetDevice();
|
||||
|
||||
KeyOfApplyClearColorValueWithDrawPipelines key =
|
||||
GetKeyOfApplyClearColorValueWithDrawPipelines(renderPassDescriptor);
|
||||
|
||||
RenderPipelineBase* pipeline = nullptr;
|
||||
DAWN_TRY_ASSIGN(pipeline, GetOrCreateApplyClearValueWithDrawPipeline(device, key));
|
||||
|
||||
Ref<BindGroupLayoutBase> layout;
|
||||
DAWN_TRY_ASSIGN(layout, pipeline->GetBindGroupLayout(0));
|
||||
|
||||
Ref<BufferBase> uniformBufferWithClearColorValues;
|
||||
DAWN_TRY_ASSIGN(uniformBufferWithClearColorValues,
|
||||
CreateUniformBufferWithClearValues(device, renderPassDescriptor, key));
|
||||
|
||||
Ref<BindGroupBase> bindGroup;
|
||||
DAWN_TRY_ASSIGN(bindGroup,
|
||||
utils::MakeBindGroup(device, layout, {{0, uniformBufferWithClearColorValues}},
|
||||
UsageValidationMode::Internal));
|
||||
|
||||
renderPassEncoder->APISetBindGroup(0, bindGroup.Get());
|
||||
renderPassEncoder->APISetPipeline(pipeline);
|
||||
renderPassEncoder->APIDraw(6);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace dawn::native
|
|
@ -0,0 +1,55 @@
|
|||
// Copyright 2022 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.
|
||||
|
||||
#ifndef SRC_DAWN_NATIVE_APPLYCLEARVALUEWITHDRAWHELPER_H_
|
||||
#define SRC_DAWN_NATIVE_APPLYCLEARVALUEWITHDRAWHELPER_H_
|
||||
|
||||
#include <bitset>
|
||||
#include <unordered_map>
|
||||
#include "dawn/common/Constants.h"
|
||||
#include "dawn/native/Error.h"
|
||||
|
||||
namespace dawn::native {
|
||||
class BufferBase;
|
||||
class RenderPassEncoder;
|
||||
struct RenderPassDescriptor;
|
||||
|
||||
struct KeyOfApplyClearColorValueWithDrawPipelines {
|
||||
uint8_t colorAttachmentCount;
|
||||
std::array<wgpu::TextureFormat, kMaxColorAttachments> colorTargetFormats;
|
||||
std::bitset<kMaxColorAttachments> colorTargetsToApplyClearColorValue;
|
||||
};
|
||||
|
||||
struct KeyOfApplyClearColorValueWithDrawPipelinesHashFunc {
|
||||
size_t operator()(KeyOfApplyClearColorValueWithDrawPipelines key) const;
|
||||
};
|
||||
struct KeyOfApplyClearColorValueWithDrawPipelinesEqualityFunc {
|
||||
bool operator()(KeyOfApplyClearColorValueWithDrawPipelines key1,
|
||||
const KeyOfApplyClearColorValueWithDrawPipelines key2) const;
|
||||
};
|
||||
using ApplyClearColorValueWithDrawPipelinesCache =
|
||||
std::unordered_map<KeyOfApplyClearColorValueWithDrawPipelines,
|
||||
Ref<RenderPipelineBase>,
|
||||
KeyOfApplyClearColorValueWithDrawPipelinesHashFunc,
|
||||
KeyOfApplyClearColorValueWithDrawPipelinesEqualityFunc>;
|
||||
|
||||
bool ShouldApplyClearBigIntegerColorValueWithDraw(const DeviceBase* device,
|
||||
const RenderPassDescriptor* renderPassDescriptor);
|
||||
|
||||
MaybeError ApplyClearBigIntegerColorValueWithDraw(RenderPassEncoder* renderPassEncoder,
|
||||
const RenderPassDescriptor* renderPassDescriptor);
|
||||
|
||||
} // namespace dawn::native
|
||||
|
||||
#endif
|
|
@ -175,6 +175,8 @@ source_set("sources") {
|
|||
sources += [
|
||||
"Adapter.cpp",
|
||||
"Adapter.h",
|
||||
"ApplyClearColorValueWithDrawHelper.cpp",
|
||||
"ApplyClearColorValueWithDrawHelper.h",
|
||||
"AsyncTask.cpp",
|
||||
"AsyncTask.h",
|
||||
"AttachmentState.cpp",
|
||||
|
|
|
@ -32,6 +32,8 @@ target_sources(dawn_native PRIVATE
|
|||
${DAWN_NATIVE_UTILS_GEN_SOURCES}
|
||||
"Adapter.cpp"
|
||||
"Adapter.h"
|
||||
"ApplyClearColorValueWithDrawHelper.cpp"
|
||||
"ApplyClearColorValueWithDrawHelper.h"
|
||||
"AsyncTask.cpp"
|
||||
"AsyncTask.h"
|
||||
"AttachmentState.cpp"
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "dawn/common/BitSetIterator.h"
|
||||
#include "dawn/common/Math.h"
|
||||
#include "dawn/native/ApplyClearColorValueWithDrawHelper.h"
|
||||
#include "dawn/native/BindGroup.h"
|
||||
#include "dawn/native/Buffer.h"
|
||||
#include "dawn/native/ChainUtils_autogen.h"
|
||||
|
@ -44,11 +45,6 @@ namespace dawn::native {
|
|||
|
||||
namespace {
|
||||
|
||||
bool HasDeprecatedColor(const RenderPassColorAttachment& attachment) {
|
||||
return !std::isnan(attachment.clearColor.r) || !std::isnan(attachment.clearColor.g) ||
|
||||
!std::isnan(attachment.clearColor.b) || !std::isnan(attachment.clearColor.a);
|
||||
}
|
||||
|
||||
MaybeError ValidateB2BCopyAlignment(uint64_t dataSize, uint64_t srcOffset, uint64_t dstOffset) {
|
||||
// Copy size must be a multiple of 4 bytes on macOS.
|
||||
DAWN_INVALID_IF(dataSize % 4 != 0, "Copy size (%u) is not a multiple of 4.", dataSize);
|
||||
|
@ -654,6 +650,13 @@ bool IsReadOnlyDepthStencilAttachment(
|
|||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool HasDeprecatedColor(const RenderPassColorAttachment& attachment) {
|
||||
return !std::isnan(attachment.clearColor.r) || !std::isnan(attachment.clearColor.g) ||
|
||||
!std::isnan(attachment.clearColor.b) || !std::isnan(attachment.clearColor.a);
|
||||
}
|
||||
|
||||
Color ClampClearColorValueToLegalRange(const Color& originalColor, const Format& format) {
|
||||
const AspectInfo& aspectInfo = format.GetAspectInfo(Aspect::Color);
|
||||
double minValue = 0;
|
||||
|
@ -688,8 +691,6 @@ Color ClampClearColorValueToLegalRange(const Color& originalColor, const Format&
|
|||
std::clamp(originalColor.a, minValue, maxValue)};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
MaybeError ValidateCommandEncoderDescriptor(const DeviceBase* device,
|
||||
const CommandEncoderDescriptor* descriptor) {
|
||||
DAWN_TRY(ValidateSingleSType(descriptor->nextInChain,
|
||||
|
@ -997,6 +998,15 @@ Ref<RenderPassEncoder> CommandEncoder::BeginRenderPass(const RenderPassDescripto
|
|||
device, descriptor, this, &mEncodingContext, std::move(usageTracker),
|
||||
std::move(attachmentState), width, height, depthReadOnly, stencilReadOnly);
|
||||
mEncodingContext.EnterPass(passEncoder.Get());
|
||||
|
||||
if (ShouldApplyClearBigIntegerColorValueWithDraw(device, descriptor)) {
|
||||
MaybeError error =
|
||||
ApplyClearBigIntegerColorValueWithDraw(passEncoder.Get(), descriptor);
|
||||
if (error.IsError()) {
|
||||
return RenderPassEncoder::MakeError(device, this, &mEncodingContext);
|
||||
}
|
||||
}
|
||||
|
||||
return passEncoder;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,10 @@ namespace dawn::native {
|
|||
|
||||
enum class UsageValidationMode;
|
||||
|
||||
bool HasDeprecatedColor(const RenderPassColorAttachment& attachment);
|
||||
|
||||
Color ClampClearColorValueToLegalRange(const Color& originalColor, const Format& format);
|
||||
|
||||
MaybeError ValidateCommandEncoderDescriptor(const DeviceBase* device,
|
||||
const CommandEncoderDescriptor* descriptor);
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "dawn/native/ApplyClearColorValueWithDrawHelper.h"
|
||||
#include "dawn/native/ObjectBase.h"
|
||||
#include "dawn/native/ScratchBuffer.h"
|
||||
#include "dawn/native/dawn_platform.h"
|
||||
|
@ -40,6 +41,8 @@ struct InternalPipelineStore {
|
|||
Ref<ComputePipelineBase> timestampComputePipeline;
|
||||
Ref<ShaderModuleBase> timestampCS;
|
||||
|
||||
ApplyClearColorValueWithDrawPipelinesCache applyClearColorValueWithDrawPipelines;
|
||||
|
||||
Ref<ShaderModuleBase> placeholderFragmentShader;
|
||||
|
||||
// A scratch buffer suitable for use as a copy destination and storage binding.
|
||||
|
|
|
@ -295,6 +295,15 @@ static constexpr ToggleEnumAndInfoList kToggleNameAndInfoList = {{
|
|||
"0, then copy from the temporary buffer to the destination. Now this toggle must be enabled "
|
||||
"on the D3D12 platforms where programmable MSAA is not supported.",
|
||||
"https://crbug.com/dawn/727"}},
|
||||
{Toggle::ApplyClearBigIntegerColorValueWithDraw,
|
||||
{"apply_clear_big_integer_color_value_with_draw",
|
||||
"Apply the clear value of the color attachment with a draw call when load op is 'clear'. "
|
||||
"This toggle is enabled by default on D3D12 backends when we set large integer values "
|
||||
"(> 2^24 or < -2^24 for signed integer formats) as the clear value of a color attachment "
|
||||
"with 32-bit integer or unsigned integer formats because D3D12 APIs only support using "
|
||||
"float numbers as clear values, while a float number cannot always precisely represent an "
|
||||
"integer that is greater than 2^24 or smaller than -2^24).",
|
||||
"https://crbug.com/dawn/537"}},
|
||||
// Comment to separate the }} so it is clearer what to copy-paste to add a toggle.
|
||||
}};
|
||||
} // anonymous namespace
|
||||
|
|
|
@ -76,6 +76,7 @@ enum class Toggle {
|
|||
D3D12AlwaysUseTypelessFormatsForCastableTexture,
|
||||
D3D12AllocateExtraMemoryFor2DArrayTexture,
|
||||
D3D12UseTempBufferInDepthStencilTextureAndBufferCopyWithNonZeroBufferOffset,
|
||||
ApplyClearBigIntegerColorValueWithDraw,
|
||||
|
||||
EnumCount,
|
||||
InvalidEnum = EnumCount,
|
||||
|
|
|
@ -639,6 +639,7 @@ void Device::InitTogglesFromDriver() {
|
|||
SetToggle(Toggle::UseDXC, false);
|
||||
SetToggle(Toggle::D3D12AlwaysUseTypelessFormatsForCastableTexture,
|
||||
!GetDeviceInfo().supportsCastingFullyTypedFormat);
|
||||
SetToggle(Toggle::ApplyClearBigIntegerColorValueWithDraw, true);
|
||||
|
||||
// The restriction on the source box specifying a portion of the depth stencil texture in
|
||||
// CopyTextureRegion() is only available on the D3D12 platforms which doesn't support
|
||||
|
|
|
@ -235,10 +235,6 @@ TEST_P(RenderPassLoadOpTests, LoadOpClearOnIntegerFormats) {
|
|||
|
||||
// This test verifies that input double values are being rendered correctly when clearing.
|
||||
TEST_P(RenderPassLoadOpTests, LoadOpClearIntegerFormatsToLargeValues) {
|
||||
// TODO(http://crbug.com/dawn/537): Implemement a workaround to enable clearing integer formats
|
||||
// to large values on D3D12.
|
||||
DAWN_SUPPRESS_TEST_IF(IsD3D12());
|
||||
|
||||
// TODO(crbug.com/dawn/1109): Re-enable once fixed on Mac Mini 8,1s w/ 11.5.
|
||||
DAWN_SUPPRESS_TEST_IF(IsMetal() && IsIntel() && IsMacOS(11, 5));
|
||||
|
||||
|
@ -389,10 +385,6 @@ TEST_P(RenderPassLoadOpTests, LoadOpClearIntegerFormatsOutOfBound_Sint16) {
|
|||
// Test clearing a color attachment on Uint32 formats (R32Uint, RG32Uint, RGBA32Uint) when the clear
|
||||
// values are out of bound.
|
||||
TEST_P(RenderPassLoadOpTests, LoadOpClearIntegerFormatsOutOfBound_Uint32) {
|
||||
// TODO(http://crbug.com/dawn/537): Implemement a workaround to enable clearing integer formats
|
||||
// to large values on D3D12.
|
||||
DAWN_SUPPRESS_TEST_IF(IsD3D12());
|
||||
|
||||
// TODO(crbug.com/dawn/1109): Re-enable once fixed on Mac Mini 8,1s w/ 11.5.
|
||||
DAWN_SUPPRESS_TEST_IF(IsMetal() && IsIntel() && IsMacOS(11, 5));
|
||||
|
||||
|
@ -424,10 +416,6 @@ TEST_P(RenderPassLoadOpTests, LoadOpClearIntegerFormatsOutOfBound_Uint32) {
|
|||
// Test clearing a color attachment on Sint32 formats (R32Sint, RG32Sint, RGBA32Sint) when the clear
|
||||
// values are out of bound.
|
||||
TEST_P(RenderPassLoadOpTests, LoadOpClearIntegerFormatsOutOfBound_Sint32) {
|
||||
// TODO(http://crbug.com/dawn/537): Implemement a workaround to enable clearing integer formats
|
||||
// to large values on D3D12.
|
||||
DAWN_SUPPRESS_TEST_IF(IsD3D12());
|
||||
|
||||
// TODO(crbug.com/dawn/1109): Re-enable once fixed on Mac Mini 8,1s w/ 11.5.
|
||||
DAWN_SUPPRESS_TEST_IF(IsMetal() && IsIntel() && IsMacOS(11, 5));
|
||||
|
||||
|
@ -499,10 +487,6 @@ TEST_P(RenderPassLoadOpTests, LoadOpClearNormalizedFormatsOutOfBound) {
|
|||
|
||||
// Test clearing multiple color attachments with different big integers can still work correctly.
|
||||
TEST_P(RenderPassLoadOpTests, LoadOpClearWithBigInt32ValuesOnMultipleColorAttachments) {
|
||||
// TODO(http://crbug.com/dawn/537): Implemement a workaround to enable clearing integer formats
|
||||
// to large values on D3D12.
|
||||
DAWN_SUPPRESS_TEST_IF(IsD3D12());
|
||||
|
||||
// TODO(crbug.com/dawn/1109): Re-enable once fixed on Mac Mini 8,1s w/ 11.5.
|
||||
DAWN_SUPPRESS_TEST_IF(IsMetal() && IsIntel() && IsMacOS(11, 5));
|
||||
|
||||
|
@ -598,10 +582,6 @@ TEST_P(RenderPassLoadOpTests, LoadOpClearWithBigInt32ValuesOnMultipleColorAttach
|
|||
// Test clearing multiple color attachments with different big unsigned integers can still work
|
||||
// correctly.
|
||||
TEST_P(RenderPassLoadOpTests, LoadOpClearWithBigUInt32ValuesOnMultipleColorAttachments) {
|
||||
// TODO(http://crbug.com/dawn/537): Implemement a workaround to enable clearing integer formats
|
||||
// to large values on D3D12.
|
||||
DAWN_SUPPRESS_TEST_IF(IsD3D12());
|
||||
|
||||
// TODO(crbug.com/dawn/1109): Re-enable once fixed on Mac Mini 8,1s w/ 11.5.
|
||||
DAWN_SUPPRESS_TEST_IF(IsMetal() && IsIntel() && IsMacOS(11, 5));
|
||||
|
||||
|
@ -716,6 +696,81 @@ TEST_P(RenderPassLoadOpTests, LoadOpClearWithBigUInt32ValuesOnMultipleColorAttac
|
|||
}
|
||||
}
|
||||
|
||||
// Test using LoadOp::Clear with different big unsigned integers as clearValues and LoadOp::Load on
|
||||
// the other color attachments in one render pass encoder works correctly.
|
||||
TEST_P(RenderPassLoadOpTests, MixedUseOfLoadOpLoadAndLoadOpClearWithBigIntegerValues) {
|
||||
// TODO(crbug.com/dawn/1109): Re-enable once fixed on Mac Mini 8,1s w/ 11.5.
|
||||
DAWN_SUPPRESS_TEST_IF(IsMetal() && IsIntel() && IsMacOS(11, 5));
|
||||
|
||||
// TODO(crbug.com/dawn/1463): Re-enable, might be the same as above just on
|
||||
// 12.4 instead of 11.5.
|
||||
DAWN_SUPPRESS_TEST_IF(IsMetal() && IsIntel() && IsMacOS(12, 4));
|
||||
|
||||
constexpr int32_t kMaxUInt32RepresentableInFloat = 1 << std::numeric_limits<float>::digits;
|
||||
|
||||
wgpu::TextureDescriptor textureDescriptor = {};
|
||||
textureDescriptor.size = {1, 1, 1};
|
||||
textureDescriptor.usage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::RenderAttachment;
|
||||
textureDescriptor.format = wgpu::TextureFormat::R32Uint;
|
||||
|
||||
wgpu::Texture textureForLoad = device.CreateTexture(&textureDescriptor);
|
||||
wgpu::Texture textureForClear = device.CreateTexture(&textureDescriptor);
|
||||
|
||||
constexpr uint32_t kExpectedLoadValue = 2u;
|
||||
// Initialize textureForLoad with pixel value 2u.
|
||||
{
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
utils::ComboRenderPassDescriptor renderPassForInit({textureForLoad.CreateView()});
|
||||
renderPassForInit.cColorAttachments[0].loadOp = wgpu::LoadOp::Clear;
|
||||
renderPassForInit.cColorAttachments[0].clearValue = {kExpectedLoadValue, 0, 0, 0};
|
||||
wgpu::RenderPassEncoder renderPassEncoder = encoder.BeginRenderPass(&renderPassForInit);
|
||||
renderPassEncoder.End();
|
||||
wgpu::CommandBuffer commandBuffer = encoder.Finish();
|
||||
queue.Submit(1, &commandBuffer);
|
||||
}
|
||||
|
||||
// Then set the load operation to Load while we still set the clear color to a big integer value
|
||||
// that cannot be represented by float.
|
||||
constexpr uint32_t kExpectedClearValue = kMaxUInt32RepresentableInFloat + 1;
|
||||
wgpu::Buffer outputBuffer;
|
||||
{
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
utils::ComboRenderPassDescriptor renderPassForClear(
|
||||
{textureForLoad.CreateView(), textureForClear.CreateView()});
|
||||
renderPassForClear.cColorAttachments[0].loadOp = wgpu::LoadOp::Load;
|
||||
renderPassForClear.cColorAttachments[0].clearValue = {kExpectedClearValue, 0, 0, 0};
|
||||
renderPassForClear.cColorAttachments[1].loadOp = wgpu::LoadOp::Clear;
|
||||
renderPassForClear.cColorAttachments[1].clearValue = {kExpectedClearValue, 0, 0, 0};
|
||||
wgpu::RenderPassEncoder renderPassEncoder = encoder.BeginRenderPass(&renderPassForClear);
|
||||
renderPassEncoder.End();
|
||||
|
||||
wgpu::BufferDescriptor bufferDescriptor = {};
|
||||
bufferDescriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
|
||||
bufferDescriptor.size = 2 * sizeof(uint32_t);
|
||||
outputBuffer = device.CreateBuffer(&bufferDescriptor);
|
||||
|
||||
wgpu::ImageCopyTexture imageCopyTextureForLoad =
|
||||
utils::CreateImageCopyTexture(textureForLoad, 0, {0, 0, 0});
|
||||
wgpu::ImageCopyBuffer imageCopyBufferForLoad =
|
||||
utils::CreateImageCopyBuffer(outputBuffer, 0, kTextureBytesPerRowAlignment);
|
||||
encoder.CopyTextureToBuffer(&imageCopyTextureForLoad, &imageCopyBufferForLoad,
|
||||
&textureDescriptor.size);
|
||||
|
||||
wgpu::ImageCopyTexture imageCopyTextureForClear =
|
||||
utils::CreateImageCopyTexture(textureForClear, 0, {0, 0, 0});
|
||||
wgpu::ImageCopyBuffer imageCopyBufferForClear = utils::CreateImageCopyBuffer(
|
||||
outputBuffer, sizeof(uint32_t), kTextureBytesPerRowAlignment);
|
||||
encoder.CopyTextureToBuffer(&imageCopyTextureForClear, &imageCopyBufferForClear,
|
||||
&textureDescriptor.size);
|
||||
|
||||
wgpu::CommandBuffer commandBuffer = encoder.Finish();
|
||||
queue.Submit(1, &commandBuffer);
|
||||
}
|
||||
|
||||
constexpr std::array<uint32_t, 2> kExpectedData = {kExpectedLoadValue, kExpectedClearValue};
|
||||
EXPECT_BUFFER_U32_RANGE_EQ(kExpectedData.data(), outputBuffer, 0, kExpectedData.size());
|
||||
}
|
||||
|
||||
DAWN_INSTANTIATE_TEST(RenderPassLoadOpTests,
|
||||
D3D12Backend(),
|
||||
MetalBackend(),
|
||||
|
|
Loading…
Reference in New Issue