blob: 59c5d2e7e38f40f842194df8d59171e22bd5a1a7 [file] [log] [blame]
// Copyright 2024 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/hlsl/writer/raise/pixel_local.h"
#include <gtest/gtest.h>
#include <tuple>
#include "src/tint/lang/core/fluent_types.h"
#include "src/tint/lang/core/ir/clone_context.h"
#include "src/tint/lang/core/ir/function.h"
#include "src/tint/lang/core/ir/transform/helper_test.h"
#include "src/tint/lang/core/number.h"
using namespace tint::core::fluent_types; // NOLINT
using namespace tint::core::number_suffixes; // NOLINT
namespace tint::hlsl::writer::raise {
namespace {
constexpr auto pixel_local = core::AddressSpace::kPixelLocal;
struct HlslWriterPixelLocalTest : core::ir::transform::TransformTest {
struct Result {
core::ir::Function* func;
core::ir::Var* pl;
};
Result OneArgFunc(bool multiple_builtins = false) {
auto* pixel_local_struct_ty =
ty.Struct(mod.symbols.New("PixelLocal"), {
{mod.symbols.New("a"), ty.u32()},
});
auto* pl = b.Var("pl", ty.ptr<pixel_local>(pixel_local_struct_ty));
mod.root_block->Append(pl);
Vector<core::type::Manager::StructMemberDesc, 3> members;
core::IOAttributes attrs;
attrs.builtin = core::BuiltinValue::kPosition;
members.Emplace(mod.symbols.New("pos"), ty.vec4<f32>(), attrs);
if (multiple_builtins) {
attrs.builtin = core::BuiltinValue::kFrontFacing;
members.Emplace(mod.symbols.New("front_facing"), ty.bool_(), attrs);
attrs.builtin = core::BuiltinValue::kSampleIndex;
members.Emplace(mod.symbols.New("sample_index"), ty.u32(), attrs);
}
auto* param_struct_ty = ty.Struct(mod.symbols.New("params"), members);
auto* func =
b.Function("main", ty.vec4<f32>(), core::ir::Function::PipelineStage::kFragment);
func->SetReturnLocation(0_u);
func->SetParams({b.FunctionParam(param_struct_ty)});
return {func, pl};
}
PixelLocalConfig OneArgConfig() {
PixelLocalConfig config;
config.options.attachment_formats.emplace(0, PixelLocalOptions::TexelFormat::kR32Uint);
config.options.attachments.emplace(0, 10);
config.options.group_index = 7;
return config;
}
Result ThreeArgFunc() {
auto* pixel_local_struct_ty =
ty.Struct(mod.symbols.New("PixelLocal"), {{mod.symbols.New("a"), ty.u32()},
{mod.symbols.New("b"), ty.i32()},
{mod.symbols.New("c"), ty.f32()}});
auto* pl = b.Var("pl", ty.ptr<pixel_local>(pixel_local_struct_ty));
mod.root_block->Append(pl);
core::IOAttributes attrs;
attrs.builtin = core::BuiltinValue::kPosition;
auto* param_struct_ty =
ty.Struct(mod.symbols.New("params"), {{mod.symbols.New("pos"), ty.vec4<f32>(), attrs}});
auto* func =
b.Function("main", ty.vec4<f32>(), core::ir::Function::PipelineStage::kFragment);
func->SetReturnLocation(0_u);
func->SetParams({b.FunctionParam(param_struct_ty)});
return {func, pl};
}
PixelLocalConfig ThreeArgConfig() {
PixelLocalConfig config;
config.options.attachment_formats.emplace(0, PixelLocalOptions::TexelFormat::kR32Uint);
config.options.attachment_formats.emplace(1, PixelLocalOptions::TexelFormat::kR32Sint);
config.options.attachment_formats.emplace(2, PixelLocalOptions::TexelFormat::kR32Float);
config.options.attachments.emplace(0, 10);
config.options.attachments.emplace(1, 12);
config.options.attachments.emplace(2, 14);
config.options.group_index = 7;
return config;
}
};
TEST_F(HlslWriterPixelLocalTest, Unused) {
auto r = OneArgFunc();
b.Append(r.func->Block(), [&] { //
b.Return(r.func, b.Construct<vec4<f32>>(1_f, 0_f, 0_f, 1_f));
});
auto* src = R"(
PixelLocal = struct @align(4) {
a:u32 @offset(0)
}
params = struct @align(16) {
pos:vec4<f32> @offset(0), @builtin(position)
}
$B1: { # root
%pl:ptr<pixel_local, PixelLocal, read_write> = var
}
%main = @fragment func(%3:params):vec4<f32> [@location(0)] {
$B2: {
%4:vec4<f32> = construct 1.0f, 0.0f, 0.0f, 1.0f
ret %4
}
}
)";
EXPECT_EQ(src, str());
auto* expect = src;
auto config = OneArgConfig();
Run(PixelLocal, config);
EXPECT_EQ(expect, str());
}
TEST_F(HlslWriterPixelLocalTest, UsedInEntry) {
auto r = OneArgFunc();
b.Append(r.func->Block(), [&] {
auto* access = b.Access(ty.ptr<pixel_local>(ty.u32()), r.pl, 0_u);
auto* add = b.Add<u32>(b.Load(access), 42_u);
b.Store(access, add);
b.Return(r.func, b.Construct<vec4<f32>>(1_f, 0_f, 0_f, 1_f));
});
auto* src = R"(
PixelLocal = struct @align(4) {
a:u32 @offset(0)
}
params = struct @align(16) {
pos:vec4<f32> @offset(0), @builtin(position)
}
$B1: { # root
%pl:ptr<pixel_local, PixelLocal, read_write> = var
}
%main = @fragment func(%3:params):vec4<f32> [@location(0)] {
$B2: {
%4:ptr<pixel_local, u32, read_write> = access %pl, 0u
%5:u32 = load %4
%6:u32 = add %5, 42u
store %4, %6
%7:vec4<f32> = construct 1.0f, 0.0f, 0.0f, 1.0f
ret %7
}
}
)";
EXPECT_EQ(src, str());
auto* expect = R"(
PixelLocal = struct @align(4) {
a:u32 @offset(0)
}
params = struct @align(16) {
pos:vec4<f32> @offset(0), @builtin(position)
}
$B1: { # root
%pl:ptr<private, PixelLocal, read_write> = var
%pixel_local_a:ptr<handle, hlsl.rasterizer_ordered_texture_2d<r32uint>, read> = var @binding_point(7, 10)
}
%main = @fragment func(%4:params):vec4<f32> [@location(0)] {
$B2: {
%5:vec4<f32> = access %4, 0u
%6:vec2<f32> = swizzle %5, xy
%7:vec2<u32> = convert %6
%8:hlsl.rasterizer_ordered_texture_2d<r32uint> = load %pixel_local_a
%9:vec4<u32> = %8.Load %7
%10:u32 = swizzle %9, x
%11:ptr<private, u32, read_write> = access %pl, 0u
store %11, %10
%12:ptr<private, u32, read_write> = access %pl, 0u
%13:u32 = load %12
%14:u32 = add %13, 42u
store %12, %14
%15:vec4<f32> = construct 1.0f, 0.0f, 0.0f, 1.0f
%16:ptr<private, u32, read_write> = access %pl, 0u
%17:vec4<u32> = swizzle %16, xxxx
%18:hlsl.rasterizer_ordered_texture_2d<r32uint> = load %pixel_local_a
%19:void = hlsl.textureStore %18, %7, %17
ret %15
}
}
)";
auto config = OneArgConfig();
Run(PixelLocal, config);
EXPECT_EQ(expect, str());
}
TEST_F(HlslWriterPixelLocalTest, UsedInNonEntry) {
auto r = OneArgFunc();
auto* func2 = b.Function("foo", ty.void_());
b.Append(func2->Block(), [&] {
auto* access = b.Access(ty.ptr<pixel_local>(ty.u32()), r.pl, 0_u);
auto* add = b.Add<u32>(b.Load(access), 42_u);
b.Store(access, add);
b.Return(func2);
});
b.Append(r.func->Block(), [&] {
b.Call(func2);
b.Return(r.func, b.Construct<vec4<f32>>(1_f, 0_f, 0_f, 1_f));
});
auto* src = R"(
PixelLocal = struct @align(4) {
a:u32 @offset(0)
}
params = struct @align(16) {
pos:vec4<f32> @offset(0), @builtin(position)
}
$B1: { # root
%pl:ptr<pixel_local, PixelLocal, read_write> = var
}
%main = @fragment func(%3:params):vec4<f32> [@location(0)] {
$B2: {
%4:void = call %foo
%6:vec4<f32> = construct 1.0f, 0.0f, 0.0f, 1.0f
ret %6
}
}
%foo = func():void {
$B3: {
%7:ptr<pixel_local, u32, read_write> = access %pl, 0u
%8:u32 = load %7
%9:u32 = add %8, 42u
store %7, %9
ret
}
}
)";
EXPECT_EQ(src, str());
auto* expect = R"(
PixelLocal = struct @align(4) {
a:u32 @offset(0)
}
params = struct @align(16) {
pos:vec4<f32> @offset(0), @builtin(position)
}
$B1: { # root
%pl:ptr<private, PixelLocal, read_write> = var
%pixel_local_a:ptr<handle, hlsl.rasterizer_ordered_texture_2d<r32uint>, read> = var @binding_point(7, 10)
}
%main = @fragment func(%4:params):vec4<f32> [@location(0)] {
$B2: {
%5:vec4<f32> = access %4, 0u
%6:vec2<f32> = swizzle %5, xy
%7:vec2<u32> = convert %6
%8:hlsl.rasterizer_ordered_texture_2d<r32uint> = load %pixel_local_a
%9:vec4<u32> = %8.Load %7
%10:u32 = swizzle %9, x
%11:ptr<private, u32, read_write> = access %pl, 0u
store %11, %10
%12:void = call %foo
%14:vec4<f32> = construct 1.0f, 0.0f, 0.0f, 1.0f
%15:ptr<private, u32, read_write> = access %pl, 0u
%16:vec4<u32> = swizzle %15, xxxx
%17:hlsl.rasterizer_ordered_texture_2d<r32uint> = load %pixel_local_a
%18:void = hlsl.textureStore %17, %7, %16
ret %14
}
}
%foo = func():void {
$B3: {
%19:ptr<private, u32, read_write> = access %pl, 0u
%20:u32 = load %19
%21:u32 = add %20, 42u
store %19, %21
ret
}
}
)";
auto config = OneArgConfig();
Run(PixelLocal, config);
EXPECT_EQ(expect, str());
}
TEST_F(HlslWriterPixelLocalTest, UsedInNonEntryViaPointer) {
auto r = OneArgFunc();
auto* func2 = b.Function("foo", ty.void_());
b.Append(func2->Block(), [&] {
auto* access = b.Access(ty.ptr<pixel_local>(ty.u32()), r.pl, 0_u);
auto* p = b.Let("p", access);
auto* add = b.Add<u32>(b.Load(p), 42_u);
b.Store(access, add);
b.Return(func2);
});
b.Append(r.func->Block(), [&] {
b.Call(func2);
b.Return(r.func, b.Construct<vec4<f32>>(1_f, 0_f, 0_f, 1_f));
});
auto* src = R"(
PixelLocal = struct @align(4) {
a:u32 @offset(0)
}
params = struct @align(16) {
pos:vec4<f32> @offset(0), @builtin(position)
}
$B1: { # root
%pl:ptr<pixel_local, PixelLocal, read_write> = var
}
%main = @fragment func(%3:params):vec4<f32> [@location(0)] {
$B2: {
%4:void = call %foo
%6:vec4<f32> = construct 1.0f, 0.0f, 0.0f, 1.0f
ret %6
}
}
%foo = func():void {
$B3: {
%7:ptr<pixel_local, u32, read_write> = access %pl, 0u
%p:ptr<pixel_local, u32, read_write> = let %7
%9:u32 = load %p
%10:u32 = add %9, 42u
store %7, %10
ret
}
}
)";
EXPECT_EQ(src, str());
auto* expect = R"(
PixelLocal = struct @align(4) {
a:u32 @offset(0)
}
params = struct @align(16) {
pos:vec4<f32> @offset(0), @builtin(position)
}
$B1: { # root
%pl:ptr<private, PixelLocal, read_write> = var
%pixel_local_a:ptr<handle, hlsl.rasterizer_ordered_texture_2d<r32uint>, read> = var @binding_point(7, 10)
}
%main = @fragment func(%4:params):vec4<f32> [@location(0)] {
$B2: {
%5:vec4<f32> = access %4, 0u
%6:vec2<f32> = swizzle %5, xy
%7:vec2<u32> = convert %6
%8:hlsl.rasterizer_ordered_texture_2d<r32uint> = load %pixel_local_a
%9:vec4<u32> = %8.Load %7
%10:u32 = swizzle %9, x
%11:ptr<private, u32, read_write> = access %pl, 0u
store %11, %10
%12:void = call %foo
%14:vec4<f32> = construct 1.0f, 0.0f, 0.0f, 1.0f
%15:ptr<private, u32, read_write> = access %pl, 0u
%16:vec4<u32> = swizzle %15, xxxx
%17:hlsl.rasterizer_ordered_texture_2d<r32uint> = load %pixel_local_a
%18:void = hlsl.textureStore %17, %7, %16
ret %14
}
}
%foo = func():void {
$B3: {
%19:ptr<private, u32, read_write> = access %pl, 0u
%20:u32 = load %19
%21:u32 = add %20, 42u
store %19, %21
ret
}
}
)";
auto config = OneArgConfig();
Run(PixelLocal, config);
EXPECT_EQ(expect, str());
}
TEST_F(HlslWriterPixelLocalTest, MultipleInputBuiltins) {
auto r = OneArgFunc(/*multiple_builtins*/ true);
b.Append(r.func->Block(), [&] {
auto* access = b.Access(ty.ptr<pixel_local>(ty.u32()), r.pl, 0_u);
auto* add = b.Add<u32>(b.Load(access), 42_u);
b.Store(access, add);
b.Return(r.func, b.Construct<vec4<f32>>(1_f, 0_f, 0_f, 1_f));
});
auto* src = R"(
PixelLocal = struct @align(4) {
a:u32 @offset(0)
}
params = struct @align(16) {
pos:vec4<f32> @offset(0), @builtin(position)
front_facing:bool @offset(16), @builtin(front_facing)
sample_index:u32 @offset(20), @builtin(sample_index)
}
$B1: { # root
%pl:ptr<pixel_local, PixelLocal, read_write> = var
}
%main = @fragment func(%3:params):vec4<f32> [@location(0)] {
$B2: {
%4:ptr<pixel_local, u32, read_write> = access %pl, 0u
%5:u32 = load %4
%6:u32 = add %5, 42u
store %4, %6
%7:vec4<f32> = construct 1.0f, 0.0f, 0.0f, 1.0f
ret %7
}
}
)";
EXPECT_EQ(src, str());
auto* expect = R"(
PixelLocal = struct @align(4) {
a:u32 @offset(0)
}
params = struct @align(16) {
pos:vec4<f32> @offset(0), @builtin(position)
front_facing:bool @offset(16), @builtin(front_facing)
sample_index:u32 @offset(20), @builtin(sample_index)
}
$B1: { # root
%pl:ptr<private, PixelLocal, read_write> = var
%pixel_local_a:ptr<handle, hlsl.rasterizer_ordered_texture_2d<r32uint>, read> = var @binding_point(7, 10)
}
%main = @fragment func(%4:params):vec4<f32> [@location(0)] {
$B2: {
%5:vec4<f32> = access %4, 0u
%6:vec2<f32> = swizzle %5, xy
%7:vec2<u32> = convert %6
%8:hlsl.rasterizer_ordered_texture_2d<r32uint> = load %pixel_local_a
%9:vec4<u32> = %8.Load %7
%10:u32 = swizzle %9, x
%11:ptr<private, u32, read_write> = access %pl, 0u
store %11, %10
%12:ptr<private, u32, read_write> = access %pl, 0u
%13:u32 = load %12
%14:u32 = add %13, 42u
store %12, %14
%15:vec4<f32> = construct 1.0f, 0.0f, 0.0f, 1.0f
%16:ptr<private, u32, read_write> = access %pl, 0u
%17:vec4<u32> = swizzle %16, xxxx
%18:hlsl.rasterizer_ordered_texture_2d<r32uint> = load %pixel_local_a
%19:void = hlsl.textureStore %18, %7, %17
ret %15
}
}
)";
auto config = OneArgConfig();
Run(PixelLocal, config);
EXPECT_EQ(expect, str());
}
TEST_F(HlslWriterPixelLocalTest, MultipleEntryPoints) {
auto* pixel_local_struct_ty =
ty.Struct(mod.symbols.New("PixelLocal"), {
{mod.symbols.New("a"), ty.u32()},
});
auto* pl = b.Var("pl", ty.ptr<pixel_local>(pixel_local_struct_ty));
mod.root_block->Append(pl);
Vector<core::type::Manager::StructMemberDesc, 3> members;
core::IOAttributes attrs;
attrs.builtin = core::BuiltinValue::kPosition;
members.Emplace(mod.symbols.New("pos"), ty.vec4<f32>(), attrs);
auto* param_struct_ty = ty.Struct(mod.symbols.New("params"), members);
for (size_t i = 0; i < 3; ++i) {
auto* func = b.Function("main" + std::to_string(i), ty.vec4<f32>(),
core::ir::Function::PipelineStage::kFragment);
func->SetReturnLocation(0_u);
func->SetParams({b.FunctionParam(param_struct_ty)});
b.Append(func->Block(), [&] {
auto* access = b.Access(ty.ptr<pixel_local>(ty.u32()), pl, 0_u);
auto* add = b.Add<u32>(b.Load(access), 42_u);
b.Store(access, add);
b.Return(func, b.Construct<vec4<f32>>(1_f, 0_f, 0_f, 1_f));
});
}
auto* src = R"(
PixelLocal = struct @align(4) {
a:u32 @offset(0)
}
params = struct @align(16) {
pos:vec4<f32> @offset(0), @builtin(position)
}
$B1: { # root
%pl:ptr<pixel_local, PixelLocal, read_write> = var
}
%main0 = @fragment func(%3:params):vec4<f32> [@location(0)] {
$B2: {
%4:ptr<pixel_local, u32, read_write> = access %pl, 0u
%5:u32 = load %4
%6:u32 = add %5, 42u
store %4, %6
%7:vec4<f32> = construct 1.0f, 0.0f, 0.0f, 1.0f
ret %7
}
}
%main1 = @fragment func(%9:params):vec4<f32> [@location(0)] {
$B3: {
%10:ptr<pixel_local, u32, read_write> = access %pl, 0u
%11:u32 = load %10
%12:u32 = add %11, 42u
store %10, %12
%13:vec4<f32> = construct 1.0f, 0.0f, 0.0f, 1.0f
ret %13
}
}
%main2 = @fragment func(%15:params):vec4<f32> [@location(0)] {
$B4: {
%16:ptr<pixel_local, u32, read_write> = access %pl, 0u
%17:u32 = load %16
%18:u32 = add %17, 42u
store %16, %18
%19:vec4<f32> = construct 1.0f, 0.0f, 0.0f, 1.0f
ret %19
}
}
)";
EXPECT_EQ(src, str());
auto* expect = R"(
PixelLocal = struct @align(4) {
a:u32 @offset(0)
}
params = struct @align(16) {
pos:vec4<f32> @offset(0), @builtin(position)
}
$B1: { # root
%pl:ptr<private, PixelLocal, read_write> = var
%pixel_local_a:ptr<handle, hlsl.rasterizer_ordered_texture_2d<r32uint>, read> = var @binding_point(7, 10)
}
%main0 = @fragment func(%4:params):vec4<f32> [@location(0)] {
$B2: {
%5:vec4<f32> = access %4, 0u
%6:vec2<f32> = swizzle %5, xy
%7:vec2<u32> = convert %6
%8:hlsl.rasterizer_ordered_texture_2d<r32uint> = load %pixel_local_a
%9:vec4<u32> = %8.Load %7
%10:u32 = swizzle %9, x
%11:ptr<private, u32, read_write> = access %pl, 0u
store %11, %10
%12:ptr<private, u32, read_write> = access %pl, 0u
%13:u32 = load %12
%14:u32 = add %13, 42u
store %12, %14
%15:vec4<f32> = construct 1.0f, 0.0f, 0.0f, 1.0f
%16:ptr<private, u32, read_write> = access %pl, 0u
%17:vec4<u32> = swizzle %16, xxxx
%18:hlsl.rasterizer_ordered_texture_2d<r32uint> = load %pixel_local_a
%19:void = hlsl.textureStore %18, %7, %17
ret %15
}
}
%main1 = @fragment func(%21:params):vec4<f32> [@location(0)] {
$B3: {
%22:vec4<f32> = access %21, 0u
%23:vec2<f32> = swizzle %22, xy
%24:vec2<u32> = convert %23
%25:hlsl.rasterizer_ordered_texture_2d<r32uint> = load %pixel_local_a
%26:vec4<u32> = %25.Load %24
%27:u32 = swizzle %26, x
%28:ptr<private, u32, read_write> = access %pl, 0u
store %28, %27
%29:ptr<private, u32, read_write> = access %pl, 0u
%30:u32 = load %29
%31:u32 = add %30, 42u
store %29, %31
%32:vec4<f32> = construct 1.0f, 0.0f, 0.0f, 1.0f
%33:ptr<private, u32, read_write> = access %pl, 0u
%34:vec4<u32> = swizzle %33, xxxx
%35:hlsl.rasterizer_ordered_texture_2d<r32uint> = load %pixel_local_a
%36:void = hlsl.textureStore %35, %24, %34
ret %32
}
}
%main2 = @fragment func(%38:params):vec4<f32> [@location(0)] {
$B4: {
%39:vec4<f32> = access %38, 0u
%40:vec2<f32> = swizzle %39, xy
%41:vec2<u32> = convert %40
%42:hlsl.rasterizer_ordered_texture_2d<r32uint> = load %pixel_local_a
%43:vec4<u32> = %42.Load %41
%44:u32 = swizzle %43, x
%45:ptr<private, u32, read_write> = access %pl, 0u
store %45, %44
%46:ptr<private, u32, read_write> = access %pl, 0u
%47:u32 = load %46
%48:u32 = add %47, 42u
store %46, %48
%49:vec4<f32> = construct 1.0f, 0.0f, 0.0f, 1.0f
%50:ptr<private, u32, read_write> = access %pl, 0u
%51:vec4<u32> = swizzle %50, xxxx
%52:hlsl.rasterizer_ordered_texture_2d<r32uint> = load %pixel_local_a
%53:void = hlsl.textureStore %52, %41, %51
ret %49
}
}
)";
auto config = OneArgConfig();
Run(PixelLocal, config);
EXPECT_EQ(expect, str());
}
TEST_F(HlslWriterPixelLocalTest, MultipleMembers) {
auto r = ThreeArgFunc();
b.Append(r.func->Block(), [&] {
auto* access = b.Access(ty.ptr<pixel_local>(ty.u32()), r.pl, 0_u);
auto* add = b.Add<u32>(b.Load(access), 42_u);
b.Store(access, add);
b.Return(r.func, b.Construct<vec4<f32>>(1_f, 0_f, 0_f, 1_f));
});
auto* src = R"(
PixelLocal = struct @align(4) {
a:u32 @offset(0)
b:i32 @offset(4)
c:f32 @offset(8)
}
params = struct @align(16) {
pos:vec4<f32> @offset(0), @builtin(position)
}
$B1: { # root
%pl:ptr<pixel_local, PixelLocal, read_write> = var
}
%main = @fragment func(%3:params):vec4<f32> [@location(0)] {
$B2: {
%4:ptr<pixel_local, u32, read_write> = access %pl, 0u
%5:u32 = load %4
%6:u32 = add %5, 42u
store %4, %6
%7:vec4<f32> = construct 1.0f, 0.0f, 0.0f, 1.0f
ret %7
}
}
)";
EXPECT_EQ(src, str());
auto* expect = R"(
PixelLocal = struct @align(4) {
a:u32 @offset(0)
b:i32 @offset(4)
c:f32 @offset(8)
}
params = struct @align(16) {
pos:vec4<f32> @offset(0), @builtin(position)
}
$B1: { # root
%pl:ptr<private, PixelLocal, read_write> = var
%pixel_local_a:ptr<handle, hlsl.rasterizer_ordered_texture_2d<r32uint>, read> = var @binding_point(7, 10)
%pixel_local_b:ptr<handle, hlsl.rasterizer_ordered_texture_2d<r32sint>, read> = var @binding_point(7, 12)
%pixel_local_c:ptr<handle, hlsl.rasterizer_ordered_texture_2d<r32float>, read> = var @binding_point(7, 14)
}
%main = @fragment func(%6:params):vec4<f32> [@location(0)] {
$B2: {
%7:vec4<f32> = access %6, 0u
%8:vec2<f32> = swizzle %7, xy
%9:vec2<u32> = convert %8
%10:hlsl.rasterizer_ordered_texture_2d<r32uint> = load %pixel_local_a
%11:vec4<u32> = %10.Load %9
%12:u32 = swizzle %11, x
%13:ptr<private, u32, read_write> = access %pl, 0u
store %13, %12
%14:hlsl.rasterizer_ordered_texture_2d<r32sint> = load %pixel_local_b
%15:vec4<i32> = %14.Load %9
%16:i32 = swizzle %15, x
%17:ptr<private, i32, read_write> = access %pl, 1u
store %17, %16
%18:hlsl.rasterizer_ordered_texture_2d<r32float> = load %pixel_local_c
%19:vec4<f32> = %18.Load %9
%20:f32 = swizzle %19, x
%21:ptr<private, f32, read_write> = access %pl, 2u
store %21, %20
%22:ptr<private, u32, read_write> = access %pl, 0u
%23:u32 = load %22
%24:u32 = add %23, 42u
store %22, %24
%25:vec4<f32> = construct 1.0f, 0.0f, 0.0f, 1.0f
%26:ptr<private, u32, read_write> = access %pl, 0u
%27:vec4<u32> = swizzle %26, xxxx
%28:hlsl.rasterizer_ordered_texture_2d<r32uint> = load %pixel_local_a
%29:void = hlsl.textureStore %28, %9, %27
%30:ptr<private, i32, read_write> = access %pl, 1u
%31:vec4<i32> = swizzle %30, xxxx
%32:hlsl.rasterizer_ordered_texture_2d<r32sint> = load %pixel_local_b
%33:void = hlsl.textureStore %32, %9, %31
%34:ptr<private, f32, read_write> = access %pl, 2u
%35:vec4<f32> = swizzle %34, xxxx
%36:hlsl.rasterizer_ordered_texture_2d<r32float> = load %pixel_local_c
%37:void = hlsl.textureStore %36, %9, %35
ret %25
}
}
)";
auto config = ThreeArgConfig();
Run(PixelLocal, config);
EXPECT_EQ(expect, str());
}
TEST_F(HlslWriterPixelLocalTest, MultipleMembers_MismatchedTypes) {
auto r = ThreeArgFunc();
b.Append(r.func->Block(), [&] {
auto* access = b.Access(ty.ptr<pixel_local>(ty.u32()), r.pl, 0_u);
auto* add = b.Add<u32>(b.Load(access), 42_u);
b.Store(access, add);
b.Return(r.func, b.Construct<vec4<f32>>(1_f, 0_f, 0_f, 1_f));
});
auto* src = R"(
PixelLocal = struct @align(4) {
a:u32 @offset(0)
b:i32 @offset(4)
c:f32 @offset(8)
}
params = struct @align(16) {
pos:vec4<f32> @offset(0), @builtin(position)
}
$B1: { # root
%pl:ptr<pixel_local, PixelLocal, read_write> = var
}
%main = @fragment func(%3:params):vec4<f32> [@location(0)] {
$B2: {
%4:ptr<pixel_local, u32, read_write> = access %pl, 0u
%5:u32 = load %4
%6:u32 = add %5, 42u
store %4, %6
%7:vec4<f32> = construct 1.0f, 0.0f, 0.0f, 1.0f
ret %7
}
}
)";
EXPECT_EQ(src, str());
auto* expect = R"(
PixelLocal = struct @align(4) {
a:u32 @offset(0)
b:i32 @offset(4)
c:f32 @offset(8)
}
params = struct @align(16) {
pos:vec4<f32> @offset(0), @builtin(position)
}
$B1: { # root
%pl:ptr<private, PixelLocal, read_write> = var
%pixel_local_a:ptr<handle, hlsl.rasterizer_ordered_texture_2d<r32float>, read> = var @binding_point(7, 10)
%pixel_local_b:ptr<handle, hlsl.rasterizer_ordered_texture_2d<r32uint>, read> = var @binding_point(7, 12)
%pixel_local_c:ptr<handle, hlsl.rasterizer_ordered_texture_2d<r32sint>, read> = var @binding_point(7, 14)
}
%main = @fragment func(%6:params):vec4<f32> [@location(0)] {
$B2: {
%7:vec4<f32> = access %6, 0u
%8:vec2<f32> = swizzle %7, xy
%9:vec2<u32> = convert %8
%10:hlsl.rasterizer_ordered_texture_2d<r32float> = load %pixel_local_a
%11:vec4<f32> = %10.Load %9
%12:f32 = swizzle %11, x
%13:u32 = convert %12
%14:ptr<private, u32, read_write> = access %pl, 0u
store %14, %13
%15:hlsl.rasterizer_ordered_texture_2d<r32uint> = load %pixel_local_b
%16:vec4<u32> = %15.Load %9
%17:u32 = swizzle %16, x
%18:i32 = convert %17
%19:ptr<private, i32, read_write> = access %pl, 1u
store %19, %18
%20:hlsl.rasterizer_ordered_texture_2d<r32sint> = load %pixel_local_c
%21:vec4<i32> = %20.Load %9
%22:i32 = swizzle %21, x
%23:f32 = convert %22
%24:ptr<private, f32, read_write> = access %pl, 2u
store %24, %23
%25:ptr<private, u32, read_write> = access %pl, 0u
%26:u32 = load %25
%27:u32 = add %26, 42u
store %25, %27
%28:vec4<f32> = construct 1.0f, 0.0f, 0.0f, 1.0f
%29:ptr<private, u32, read_write> = access %pl, 0u
%30:f32 = convert %29
%31:vec4<f32> = swizzle %30, xxxx
%32:hlsl.rasterizer_ordered_texture_2d<r32float> = load %pixel_local_a
%33:void = hlsl.textureStore %32, %9, %31
%34:ptr<private, i32, read_write> = access %pl, 1u
%35:u32 = convert %34
%36:vec4<u32> = swizzle %35, xxxx
%37:hlsl.rasterizer_ordered_texture_2d<r32uint> = load %pixel_local_b
%38:void = hlsl.textureStore %37, %9, %36
%39:ptr<private, f32, read_write> = access %pl, 2u
%40:i32 = convert %39
%41:vec4<i32> = swizzle %40, xxxx
%42:hlsl.rasterizer_ordered_texture_2d<r32sint> = load %pixel_local_c
%43:void = hlsl.textureStore %42, %9, %41
ret %28
}
}
)";
auto config = ThreeArgConfig();
// Overwrite the three format types to mismatch the ones in the IR
config.options.attachment_formats[0] = PixelLocalOptions::TexelFormat::kR32Float;
config.options.attachment_formats[1] = PixelLocalOptions::TexelFormat::kR32Uint;
config.options.attachment_formats[2] = PixelLocalOptions::TexelFormat::kR32Sint;
Run(PixelLocal, config);
EXPECT_EQ(expect, str());
}
} // namespace
} // namespace tint::hlsl::writer::raise