Skip to content

Commit

Permalink
Dawn Native: Add Immediate Constant Offset Layout in Pipeline
Browse files Browse the repository at this point in the history
Pipeline has all infos about immediate constants, including
immediate data used by customer and internal constants used
by Dawn (e.g. clamp frag depth). It is possible for pipeline to
order constants tightly.

This CL adds bit set and offset map in Pipeline to provide the final
immediate constants order info. And enabled this in Vulkan backend.

Bug:366291600

Change-Id: I228bb3bffdd9966efa11c501e4cb8115cf59bd02
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/220594
Reviewed-by: Corentin Wallez <[email protected]>
Commit-Queue: Shaobo Yan <[email protected]>
Commit-Queue: Corentin Wallez <[email protected]>
  • Loading branch information
shaoboyan091 authored and Dawn LUCI CQ committed Jan 30, 2025
1 parent 67406e2 commit bd4da62
Show file tree
Hide file tree
Showing 17 changed files with 278 additions and 54 deletions.
20 changes: 20 additions & 0 deletions src/dawn/common/Compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,24 @@
#define DAWN_ATTRIBUTE_RETURNS_NONNULL
#endif

// DAWN_ENABLE_STRUCT_PADDING_WARNINGS
//
// Tells the compiler to emit a warning if the structure has any padding.
// This is helpful to avoid uninitialized bits in cache keys or other similar structures.
#if DAWN_COMPILER_IS(CLANG)
#define DAWN_ENABLE_STRUCT_PADDING_WARNINGS \
_Pragma("clang diagnostic push") _Pragma("clang diagnostic error \"-Wpadded\"")
#define DAWN_DISABLE_STRUCT_PADDING_WARNINGS _Pragma("clang diagnostic pop")
#elif DAWN_COMPILER_IS(GCC)
#define DAWN_ENABLE_STRUCT_PADDING_WARNINGS \
_Pragma("GCC diagnostic push") _Pragma("GCC diagnostic error \"-Wpadded\"")
#define DAWN_DISABLE_STRUCT_PADDING_WARNINGS _Pragma("GCC diagnostic pop")
#elif DAWN_COMPILER_IS(MSVC)
#define DAWN_ENABLE_STRUCT_PADDING_WARNINGS __pragma(warning(push)) __pragma(warning(error : 4820))
#define DAWN_DISABLE_STRUCT_PADDING_WARNINGS __pragma(warning(pop))
#else
#define DAWN_ENABLE_STRUCT_PADDING_WARNINGS
#define DAWN_DISABLE_STRUCT_PADDING_WARNINGS
#endif

#endif // SRC_DAWN_COMMON_COMPILER_H_
5 changes: 2 additions & 3 deletions src/dawn/native/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,6 @@ source_set("sources") {
"Format.cpp",
"Format.h",
"Forward.h",
"ImmediateConstantsLayout.cpp",
"ImmediateConstantsLayout.h",
"ImmediateConstantsTracker.cpp",
"ImmediateConstantsTracker.h",
Expand Down Expand Up @@ -423,7 +422,7 @@ source_set("sources") {
}

# Only win32 app needs to link with user32.lib
# In UWP, all availiable APIs are defined in WindowsApp.lib
# In UWP, all available APIs are defined in WindowsApp.lib
if (is_win && !dawn_is_winuwp) {
libs += [
"user32.lib",
Expand Down Expand Up @@ -922,7 +921,7 @@ source_set("sources") {
dawn_component("native") {
DEFINE_PREFIX = "DAWN_NATIVE"

#Make headers publically visible
#Make headers publicly visible
public_deps = [ ":headers" ]

deps = [
Expand Down
1 change: 0 additions & 1 deletion src/dawn/native/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,6 @@ set(sources
"ExternalTexture.cpp"
"Features.cpp"
"Format.cpp"
"ImmediateConstantsLayout.cpp"
"ImmediateConstantsTracker.cpp"
"IndirectDrawMetadata.cpp"
"IndirectDrawValidationEncoder.cpp"
Expand Down
41 changes: 0 additions & 41 deletions src/dawn/native/ImmediateConstantsLayout.cpp

This file was deleted.

15 changes: 10 additions & 5 deletions src/dawn/native/ImmediateConstantsLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@
#ifndef SRC_DAWN_NATIVE_IMMEDIATECONSTANTSLAYOUT_H_
#define SRC_DAWN_NATIVE_IMMEDIATECONSTANTSLAYOUT_H_

#include <unordered_map>

#include "dawn/common/Compiler.h"
#include "dawn/common/ityp_bitset.h"
#include "dawn/native/EnumClassBitmasks.h"
#include "dawn/native/IntegerTypes.h"

namespace dawn::native {
Expand All @@ -39,6 +39,7 @@ namespace dawn::native {
// NOTE: 'offsetof' doesn't support non-standard-layout structs. So use
// aggregate instead of inheritance for RenderImmediateConstants and
// ComputeImmediateConstants.
DAWN_ENABLE_STRUCT_PADDING_WARNINGS
struct UserImmediateConstants {
uint32_t userImmediateData[kMaxExternalImmediateConstantsPerPipeline];
};
Expand All @@ -59,7 +60,6 @@ struct RenderImmediateConstants {
uint32_t firstVertex;
uint32_t firstInstance;
};
static_assert(sizeof(RenderImmediateConstants) == 32u);

struct NumWorkgroupsDimensions {
uint32_t numWorkgroupsX;
Expand All @@ -74,11 +74,16 @@ struct ComputeImmediateConstants {

NumWorkgroupsDimensions numWorkgroups;
};
static_assert(sizeof(ComputeImmediateConstants) == 28u);
DAWN_DISABLE_STRUCT_PADDING_WARNINGS

// Convert byte sizes and offsets into immediate constant indices and offsets
// (dividing everything by kImmediateConstantElementByteSize)
ImmediateConstantMask GetImmediateConstantBlockBits(size_t byteOffset, size_t byteSize);
constexpr ImmediateConstantMask GetImmediateConstantBlockBits(size_t byteOffset, size_t byteSize) {
size_t firstIndex = byteOffset / kImmediateConstantElementByteSize;
size_t constantCount = byteSize / kImmediateConstantElementByteSize;

return ((1u << constantCount) - 1u) << firstIndex;
}

} // namespace dawn::native

Expand Down
20 changes: 20 additions & 0 deletions src/dawn/native/ImmediateConstantsTracker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,18 @@ namespace dawn::native {
RenderImmediateConstantsTrackerBase::RenderImmediateConstantsTrackerBase()
: UserImmediateConstantsTrackerBase() {}

// Render pipeline changes reset all pipeline related dirty bits and
// keep frag depth dirty bits which related to viewport.
// TODO(crbug.com/366291600): Support immediate data compatible.
void RenderImmediateConstantsTrackerBase::OnPipelineChange(PipelineBase* pipeline) {
mPipelineMask = pipeline->GetPipelineMask();

// frag depth args are related to viewport instead of pipeline
static constexpr ImmediateConstantMask fragDepth = GetImmediateConstantBlockBits(
offsetof(RenderImmediateConstants, clampFragDepth), sizeof(ClampFragDepthArgs));
mDirty &= fragDepth;
}

void RenderImmediateConstantsTrackerBase::SetClampFragDepth(float minClampFragDepth,
float maxClampFragDepth) {
// Put the data in the right layout to match the RenderImmediateConstants struct
Expand All @@ -58,6 +70,14 @@ void RenderImmediateConstantsTrackerBase::SetFirstInstance(uint32_t firstInstanc

ComputeImmediateConstantsTrackerBase::ComputeImmediateConstantsTrackerBase()
: UserImmediateConstantsTrackerBase() {}

// Pipeline changes reset all dirty bits.
// TODO(crbug.com/366291600): Support immediate data compatible.
void ComputeImmediateConstantsTrackerBase::OnPipelineChange(PipelineBase* pipeline) {
mPipelineMask = pipeline->GetPipelineMask();
mDirty.reset();
}

void ComputeImmediateConstantsTrackerBase::SetNumWorkgroups(uint32_t numWorkgroupX,
uint32_t numWorkgroupY,
uint32_t numWorkgroupZ) {
Expand Down
6 changes: 6 additions & 0 deletions src/dawn/native/ImmediateConstantsTracker.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ template <typename T>
class UserImmediateConstantsTrackerBase {
public:
UserImmediateConstantsTrackerBase() {}

// Setters
void SetImmediateData(uint32_t immediateDataRangeOffset, uint32_t* values, uint32_t count) {
uint32_t* destData = mContent.template Get<uint32_t>(offsetof(T, userConstants) +
Expand All @@ -86,6 +87,8 @@ class UserImmediateConstantsTrackerBase {
}

// Getters
const ImmediateConstantMask& GetPipelineMask() const { return mPipelineMask; }

const ImmediateConstantMask& GetDirtyBits() const { return mDirty; }

const ImmediateDataContent<T>& GetContent() const { return mContent; }
Expand All @@ -105,12 +108,14 @@ class UserImmediateConstantsTrackerBase {

ImmediateDataContent<T> mContent;
ImmediateConstantMask mDirty = ImmediateConstantMask(0);
ImmediateConstantMask mPipelineMask = ImmediateConstantMask(0);
};

class RenderImmediateConstantsTrackerBase
: public UserImmediateConstantsTrackerBase<RenderImmediateConstants> {
public:
RenderImmediateConstantsTrackerBase();
void OnPipelineChange(PipelineBase* pipeline);
void SetClampFragDepth(float minClampFragDepth, float maxClampFragDepth);
void SetFirstIndexOffset(uint32_t firstVertex, uint32_t firstInstance);
void SetFirstVertex(uint32_t firstVertex);
Expand All @@ -121,6 +126,7 @@ class ComputeImmediateConstantsTrackerBase
: public UserImmediateConstantsTrackerBase<ComputeImmediateConstants> {
public:
ComputeImmediateConstantsTrackerBase();
void OnPipelineChange(PipelineBase* pipeline);
void SetNumWorkgroups(uint32_t numWorkgroupX, uint32_t numWorkgroupY, uint32_t numWorkgroupZ);
};

Expand Down
12 changes: 12 additions & 0 deletions src/dawn/native/Pipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,10 @@ ResultOrError<ShaderModuleEntryPoint> ValidateProgrammableStage(DeviceBase* devi
return entryPoint;
}

uint32_t GetRawBits(ImmediateConstantMask bits) {
return static_cast<uint32_t>(bits.to_ulong());
}

// PipelineBase

PipelineBase::PipelineBase(DeviceBase* device,
Expand Down Expand Up @@ -287,6 +291,10 @@ wgpu::ShaderStage PipelineBase::GetStageMask() const {
return mStageMask;
}

const ImmediateConstantMask& PipelineBase::GetPipelineMask() const {
return mPipelineMask;
}

MaybeError PipelineBase::ValidateGetBindGroupLayout(BindGroupIndex groupIndex) {
DAWN_TRY(GetDevice()->ValidateIsAlive());
DAWN_TRY(GetDevice()->ValidateObject(this));
Expand Down Expand Up @@ -379,4 +387,8 @@ MaybeError PipelineBase::Initialize(std::optional<ScopedUseShaderPrograms> scope
return {};
}

void PipelineBase::SetPipelineMaskForTesting(ImmediateConstantMask immediateConstantMask) {
mPipelineMask = immediateConstantMask;
}

} // namespace dawn::native
7 changes: 7 additions & 0 deletions src/dawn/native/Pipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ struct ProgrammableStage {
PipelineConstantEntries constants;
};

uint32_t GetRawBits(ImmediateConstantMask bits);

class PipelineBase : public ApiObjectBase, public CachedObject {
public:
~PipelineBase() override;
Expand All @@ -75,6 +77,7 @@ class PipelineBase : public ApiObjectBase, public CachedObject {
const PerStage<ProgrammableStage>& GetAllStages() const;
bool HasStage(SingleShaderStage stage) const;
wgpu::ShaderStage GetStageMask() const;
const ImmediateConstantMask& GetPipelineMask() const;

ResultOrError<Ref<BindGroupLayoutBase>> GetBindGroupLayout(uint32_t groupIndex);

Expand All @@ -91,13 +94,17 @@ class PipelineBase : public ApiObjectBase, public CachedObject {
// Initialize() should only be called once by the frontend.
MaybeError Initialize(std::optional<ScopedUseShaderPrograms> scopedUsePrograms = std::nullopt);

void SetPipelineMaskForTesting(ImmediateConstantMask immediateConstantMask);

protected:
PipelineBase(DeviceBase* device,
PipelineLayoutBase* layout,
StringView label,
std::vector<StageAndDescriptor> stages);
PipelineBase(DeviceBase* device, ObjectBase::ErrorTag tag, StringView label);

ImmediateConstantMask mPipelineMask = ImmediateConstantMask(0);

private:
MaybeError ValidateGetBindGroupLayout(BindGroupIndex group);

Expand Down
4 changes: 3 additions & 1 deletion src/dawn/native/RenderPipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "dawn/common/BitSetIterator.h"
#include "dawn/common/Enumerator.h"
#include "dawn/common/ityp_array.h"
#include "dawn/common/ityp_bitset.h"
#include "dawn/common/ityp_span.h"
#include "dawn/native/Adapter.h"
#include "dawn/native/ChainUtils.h"
Expand Down Expand Up @@ -948,7 +949,8 @@ std::vector<StageAndDescriptor> GetRenderStagesAndSetPlaceholderShader(
// RenderPipelineBase

RenderPipelineBase::RenderPipelineBase(DeviceBase* device,
const UnpackedPtr<RenderPipelineDescriptor>& descriptor)
const UnpackedPtr<RenderPipelineDescriptor>& descriptor,
ImmediateConstantMask requiredInternalImmediateConstants)
: PipelineBase(device,
descriptor->layout,
descriptor->label,
Expand Down
6 changes: 5 additions & 1 deletion src/dawn/native/RenderPipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "dawn/common/ContentLessObjectCacheable.h"
#include "dawn/native/AttachmentState.h"
#include "dawn/native/Forward.h"
#include "dawn/native/ImmediateConstantsLayout.h"
#include "dawn/native/IntegerTypes.h"
#include "dawn/native/Pipeline.h"

Expand Down Expand Up @@ -88,7 +89,10 @@ struct VertexBufferInfo {
class RenderPipelineBase : public PipelineBase,
public ContentLessObjectCacheable<RenderPipelineBase> {
public:
RenderPipelineBase(DeviceBase* device, const UnpackedPtr<RenderPipelineDescriptor>& descriptor);
RenderPipelineBase(
DeviceBase* device,
const UnpackedPtr<RenderPipelineDescriptor>& descriptor,
ImmediateConstantMask requiredInternalImmediateConstants = ImmediateConstantMask(0u));
~RenderPipelineBase() override;

static Ref<RenderPipelineBase> MakeError(DeviceBase* device, StringView label);
Expand Down
6 changes: 6 additions & 0 deletions src/dawn/native/ShaderModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,12 @@ ResultOrError<std::unique_ptr<EntryPointMetadata>> ReflectEntryPointUsingTint(
metadata->usedInterStageVariables.resize(maxInterStageShaderVariables);
metadata->interStageVariables.resize(maxInterStageShaderVariables);

// Immediate data byte size must be 4-byte aligned.
if (entryPoint.push_constant_size) {
DAWN_ASSERT(IsAligned(entryPoint.push_constant_size, 4u));
metadata->immediateDataRangeByteSize = entryPoint.push_constant_size;
}

// Vertex shader specific reflection.
if (metadata->stage == SingleShaderStage::Vertex) {
// Vertex input reflection.
Expand Down
6 changes: 6 additions & 0 deletions src/dawn/native/vulkan/ComputePipelineVk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <vector>

#include "dawn/native/CreatePipelineAsyncEvent.h"
#include "dawn/native/ImmediateConstantsLayout.h"
#include "dawn/native/vulkan/DeviceVk.h"
#include "dawn/native/vulkan/FencedDeleter.h"
#include "dawn/native/vulkan/PipelineCacheVk.h"
Expand All @@ -57,6 +58,11 @@ MaybeError ComputePipeline::InitializeImpl() {
// Vulkan devices need cache UUID field to be serialized into pipeline cache keys.
StreamIn(&mCacheKey, device->GetDeviceInfo().properties.pipelineCacheUUID);

// Set Immediate Constants states
mPipelineMask |=
GetImmediateConstantBlockBits(offsetof(ComputeImmediateConstants, userConstants),
GetLayout()->GetImmediateDataRangeByteSize());

// Compute pipeline doesn't have clamp depth feature.
// TODO(crbug.com/366291600): Setting immediate data size if needed.
DAWN_TRY(InitializeBase(layout, 0));
Expand Down
19 changes: 18 additions & 1 deletion src/dawn/native/vulkan/RenderPipelineVk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <vector>

#include "dawn/native/CreatePipelineAsyncEvent.h"
#include "dawn/native/ImmediateConstantsLayout.h"
#include "dawn/native/vulkan/DeviceVk.h"
#include "dawn/native/vulkan/FencedDeleter.h"
#include "dawn/native/vulkan/PipelineCacheVk.h"
Expand Down Expand Up @@ -345,7 +346,12 @@ VkStencilOp VulkanStencilOp(wgpu::StencilOperation op) {
Ref<RenderPipeline> RenderPipeline::CreateUninitialized(
Device* device,
const UnpackedPtr<RenderPipelineDescriptor>& descriptor) {
return AcquireRef(new RenderPipeline(device, descriptor));
// Possible required internal immediate constants for RenderPipelineVk:
// - ClampFragDepth
const ImmediateConstantMask requiredInternalConstants = GetImmediateConstantBlockBits(
offsetof(RenderImmediateConstants, clampFragDepth), sizeof(ClampFragDepthArgs));

return AcquireRef(new RenderPipeline(device, descriptor, requiredInternalConstants));
}

MaybeError RenderPipeline::InitializeImpl() {
Expand All @@ -355,6 +361,17 @@ MaybeError RenderPipeline::InitializeImpl() {
// Vulkan devices need cache UUID field to be serialized into pipeline cache keys.
StreamIn(&mCacheKey, device->GetDeviceInfo().properties.pipelineCacheUUID);

// Set immediate constant status
mPipelineMask |=
GetImmediateConstantBlockBits(offsetof(RenderImmediateConstants, userConstants),
GetLayout()->GetImmediateDataRangeByteSize());

// Gather list of internal immediate constants used by this pipeline
if (UsesFragDepth() && !HasUnclippedDepth()) {
mPipelineMask |= GetImmediateConstantBlockBits(
offsetof(RenderImmediateConstants, clampFragDepth), sizeof(ClampFragDepthArgs));
}

// There are at most 2 shader stages in render pipeline, i.e. vertex and fragment
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages;
std::array<std::string, 2> shaderStageEntryPoints;
Expand Down
Loading

0 comments on commit bd4da62

Please sign in to comment.