blob: f34138afacebab03ac3d9ab03485834117912f6f [file] [log] [blame]
// Copyright 2023 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 <utility>
#include "src/tint/lang/hlsl/writer/ast_raise/pixel_local.h"
#include "src/tint/lang/wgsl/ast/transform/helper_test.h"
namespace tint::hlsl::writer {
namespace {
struct ROVBinding {
uint32_t field_index;
uint32_t register_index;
core::TexelFormat rov_format;
};
ast::transform::DataMap Bindings(std::initializer_list<ROVBinding> bindings,
uint32_t groupIndex = 0) {
PixelLocal::Config cfg;
cfg.rov_group_index = groupIndex;
for (auto& binding : bindings) {
cfg.pls_member_to_rov_reg.Add(binding.field_index, binding.register_index);
cfg.pls_member_to_rov_format.Add(binding.field_index, binding.rov_format);
}
ast::transform::DataMap data;
data.Add<PixelLocal::Config>(std::move(cfg));
return data;
}
using HLSLPixelLocalTest = ast::transform::TransformTest;
TEST_F(HLSLPixelLocalTest, EmptyModule) {
auto* src = "";
EXPECT_FALSE(ShouldRun<PixelLocal>(src, Bindings({})));
}
TEST_F(HLSLPixelLocalTest, MissingBindings) {
auto* src = R"(
enable chromium_experimental_pixel_local;
struct PixelLocal {
a : u32,
}
var<pixel_local> P : PixelLocal;
@fragment
fn F() -> @location(0) vec4f {
P.a += 42;
return vec4f(1, 0, 0, 1);
}
)";
auto* expect = R"(error: PixelLocal::Config::attachments missing entry for field 0)";
ast::transform::DataMap data;
data.Add<PixelLocal::Config>();
auto got = Run<PixelLocal>(src, data);
EXPECT_EQ(expect, str(got));
}
TEST_F(HLSLPixelLocalTest, UseInEntryPoint_NoPosition) {
auto* src = R"(
enable chromium_experimental_pixel_local;
struct PixelLocal {
a : u32,
}
var<pixel_local> P : PixelLocal;
@fragment
fn F() -> @location(0) vec4f {
P.a += 42;
return vec4f(1, 0, 0, 1);
}
)";
auto* expect =
R"(
enable chromium_experimental_pixel_local;
@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
fn load_from_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
P.a = textureLoad(pixel_local_a, rov_texcoord).x;
}
fn store_into_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
}
struct F_res {
@location(0)
output_0 : vec4<f32>,
}
@fragment
fn F(@builtin(position) my_pos : vec4<f32>) -> F_res {
let hlsl_sv_position = my_pos;
load_from_pixel_local_storage(hlsl_sv_position);
let result = F_inner();
store_into_pixel_local_storage(hlsl_sv_position);
return F_res(result);
}
struct PixelLocal {
a : u32,
}
var<private> P : PixelLocal;
fn F_inner() -> vec4f {
P.a += 42;
return vec4f(1, 0, 0, 1);
}
)";
auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}));
EXPECT_EQ(expect, str(got));
}
TEST_F(HLSLPixelLocalTest, UseInEntryPoint_SeparatePosition) {
auto* src = R"(
enable chromium_experimental_pixel_local;
struct PixelLocal {
a : u32,
}
var<pixel_local> P : PixelLocal;
@fragment
fn F(@builtin(position) pos : vec4f) -> @location(0) vec4f {
P.a += 42;
return pos;
}
)";
auto* expect =
R"(
enable chromium_experimental_pixel_local;
@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
fn load_from_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
P.a = textureLoad(pixel_local_a, rov_texcoord).x;
}
fn store_into_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
}
struct F_res {
@location(0)
output_0 : vec4<f32>,
}
@fragment
fn F(@builtin(position) pos : vec4f) -> F_res {
let hlsl_sv_position = pos;
load_from_pixel_local_storage(hlsl_sv_position);
let result = F_inner(pos);
store_into_pixel_local_storage(hlsl_sv_position);
return F_res(result);
}
struct PixelLocal {
a : u32,
}
var<private> P : PixelLocal;
fn F_inner(pos : vec4f) -> vec4f {
P.a += 42;
return pos;
}
)";
auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}));
EXPECT_EQ(expect, str(got));
}
TEST_F(HLSLPixelLocalTest, UseInEntryPoint_PositionInStruct) {
auto* src = R"(
enable chromium_experimental_pixel_local;
struct PixelLocal {
a : u32,
}
var<pixel_local> P : PixelLocal;
struct FragmentInput {
@location(0) input : vec4f,
@builtin(position) pos : vec4f,
}
@fragment
fn F(fragmentInput : FragmentInput) -> @location(0) vec4f {
P.a += 42;
return fragmentInput.input + fragmentInput.pos;
}
)";
auto* expect =
R"(
enable chromium_experimental_pixel_local;
@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
fn load_from_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
P.a = textureLoad(pixel_local_a, rov_texcoord).x;
}
fn store_into_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
}
struct F_res {
@location(0)
output_0 : vec4<f32>,
}
@fragment
fn F(fragmentInput : FragmentInput) -> F_res {
let hlsl_sv_position = fragmentInput.pos;
load_from_pixel_local_storage(hlsl_sv_position);
let result = F_inner(fragmentInput);
store_into_pixel_local_storage(hlsl_sv_position);
return F_res(result);
}
struct PixelLocal {
a : u32,
}
var<private> P : PixelLocal;
struct FragmentInput {
@location(0)
input : vec4f,
@builtin(position)
pos : vec4f,
}
fn F_inner(fragmentInput : FragmentInput) -> vec4f {
P.a += 42;
return (fragmentInput.input + fragmentInput.pos);
}
)";
auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}));
EXPECT_EQ(expect, str(got));
}
TEST_F(HLSLPixelLocalTest, UseInEntryPoint_NonZeroROVGroupIndex) {
auto* src = R"(
enable chromium_experimental_pixel_local;
struct PixelLocal {
a : u32,
}
var<pixel_local> P : PixelLocal;
struct FragmentInput {
@location(0) input : vec4f,
@builtin(position) pos : vec4f,
}
@fragment
fn F(fragmentInput : FragmentInput) -> @location(0) vec4f {
P.a += 42;
return fragmentInput.input + fragmentInput.pos;
}
)";
auto* expect =
R"(
enable chromium_experimental_pixel_local;
@binding(1) @group(3) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
fn load_from_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
P.a = textureLoad(pixel_local_a, rov_texcoord).x;
}
fn store_into_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
}
struct F_res {
@location(0)
output_0 : vec4<f32>,
}
@fragment
fn F(fragmentInput : FragmentInput) -> F_res {
let hlsl_sv_position = fragmentInput.pos;
load_from_pixel_local_storage(hlsl_sv_position);
let result = F_inner(fragmentInput);
store_into_pixel_local_storage(hlsl_sv_position);
return F_res(result);
}
struct PixelLocal {
a : u32,
}
var<private> P : PixelLocal;
struct FragmentInput {
@location(0)
input : vec4f,
@builtin(position)
pos : vec4f,
}
fn F_inner(fragmentInput : FragmentInput) -> vec4f {
P.a += 42;
return (fragmentInput.input + fragmentInput.pos);
}
)";
constexpr uint32_t kROVGroupIndex = 3u;
auto got =
Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}, kROVGroupIndex));
EXPECT_EQ(expect, str(got));
}
TEST_F(HLSLPixelLocalTest, UseInEntryPoint_Multiple_PixelLocal_Members) {
auto* src = R"(
enable chromium_experimental_pixel_local;
struct PixelLocal {
a : u32,
b : i32,
c : f32,
d : u32,
}
var<pixel_local> P : PixelLocal;
struct FragmentInput {
@location(0) input : vec4f,
@builtin(position) pos : vec4f,
}
@fragment
fn F(fragmentInput : FragmentInput) -> @location(0) vec4f {
P.a += 42;
P.b -= 21;
P.c += 12.5f;
P.d -= 5;
return fragmentInput.input + fragmentInput.pos;
}
)";
auto* expect =
R"(
enable chromium_experimental_pixel_local;
@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
@binding(2) @group(0) @internal(rov) var pixel_local_b : texture_storage_2d<r32sint, read_write>;
@binding(3) @group(0) @internal(rov) var pixel_local_c : texture_storage_2d<r32float, read_write>;
@binding(4) @group(0) @internal(rov) var pixel_local_d : texture_storage_2d<r32uint, read_write>;
fn load_from_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
P.a = textureLoad(pixel_local_a, rov_texcoord).x;
P.b = textureLoad(pixel_local_b, rov_texcoord).x;
P.c = textureLoad(pixel_local_c, rov_texcoord).x;
P.d = textureLoad(pixel_local_d, rov_texcoord).x;
}
fn store_into_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
textureStore(pixel_local_b, rov_texcoord, vec4i(P.b));
textureStore(pixel_local_c, rov_texcoord, vec4f(P.c));
textureStore(pixel_local_d, rov_texcoord, vec4u(P.d));
}
struct F_res {
@location(0)
output_0 : vec4<f32>,
}
@fragment
fn F(fragmentInput : FragmentInput) -> F_res {
let hlsl_sv_position = fragmentInput.pos;
load_from_pixel_local_storage(hlsl_sv_position);
let result = F_inner(fragmentInput);
store_into_pixel_local_storage(hlsl_sv_position);
return F_res(result);
}
struct PixelLocal {
a : u32,
b : i32,
c : f32,
d : u32,
}
var<private> P : PixelLocal;
struct FragmentInput {
@location(0)
input : vec4f,
@builtin(position)
pos : vec4f,
}
fn F_inner(fragmentInput : FragmentInput) -> vec4f {
P.a += 42;
P.b -= 21;
P.c += 12.5f;
P.d -= 5;
return (fragmentInput.input + fragmentInput.pos);
}
)";
auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint},
{1, 2, core::TexelFormat::kR32Sint},
{2, 3, core::TexelFormat::kR32Float},
{3, 4, core::TexelFormat::kR32Uint}}));
EXPECT_EQ(expect, str(got));
}
TEST_F(HLSLPixelLocalTest, UseInEntryPoint_Multiple_PixelLocal_Members_And_Fragment_Output) {
auto* src = R"(
enable chromium_experimental_pixel_local;
struct PixelLocal {
a : u32,
b : i32,
c : f32,
d : u32,
}
var<pixel_local> P : PixelLocal;
struct FragmentInput {
@location(0) input : vec4f,
@builtin(position) pos : vec4f,
}
struct FragmentOutput {
@location(0) color0 : vec4f,
@location(1) color1 : vec4f,
}
@fragment
fn F(fragmentInput : FragmentInput) -> FragmentOutput {
P.a += 42;
P.b -= 21;
P.c += 12.5f;
P.d -= 5;
return FragmentOutput(fragmentInput.input, fragmentInput.pos);
}
)";
auto* expect =
R"(
enable chromium_experimental_pixel_local;
@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
@binding(2) @group(0) @internal(rov) var pixel_local_b : texture_storage_2d<r32sint, read_write>;
@binding(3) @group(0) @internal(rov) var pixel_local_c : texture_storage_2d<r32float, read_write>;
@binding(4) @group(0) @internal(rov) var pixel_local_d : texture_storage_2d<r32uint, read_write>;
fn load_from_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
P.a = textureLoad(pixel_local_a, rov_texcoord).x;
P.b = textureLoad(pixel_local_b, rov_texcoord).x;
P.c = textureLoad(pixel_local_c, rov_texcoord).x;
P.d = textureLoad(pixel_local_d, rov_texcoord).x;
}
fn store_into_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
textureStore(pixel_local_b, rov_texcoord, vec4i(P.b));
textureStore(pixel_local_c, rov_texcoord, vec4f(P.c));
textureStore(pixel_local_d, rov_texcoord, vec4u(P.d));
}
struct F_res {
@location(0)
output_0 : vec4<f32>,
@location(1)
output_1 : vec4<f32>,
}
@fragment
fn F(fragmentInput : FragmentInput) -> F_res {
let hlsl_sv_position = fragmentInput.pos;
load_from_pixel_local_storage(hlsl_sv_position);
let result = F_inner(fragmentInput);
store_into_pixel_local_storage(hlsl_sv_position);
return F_res(result.color0, result.color1);
}
struct PixelLocal {
a : u32,
b : i32,
c : f32,
d : u32,
}
var<private> P : PixelLocal;
struct FragmentInput {
@location(0)
input : vec4f,
@builtin(position)
pos : vec4f,
}
struct FragmentOutput {
color0 : vec4f,
color1 : vec4f,
}
fn F_inner(fragmentInput : FragmentInput) -> FragmentOutput {
P.a += 42;
P.b -= 21;
P.c += 12.5f;
P.d -= 5;
return FragmentOutput(fragmentInput.input, fragmentInput.pos);
}
)";
auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint},
{1, 2, core::TexelFormat::kR32Sint},
{2, 3, core::TexelFormat::kR32Float},
{3, 4, core::TexelFormat::kR32Uint}}));
EXPECT_EQ(expect, str(got));
}
TEST_F(HLSLPixelLocalTest, ROV_Format_Different_From_Pixel_Local_Member_Format) {
auto* src = R"(
enable chromium_experimental_pixel_local;
struct PixelLocal {
a : u32,
b : i32,
c : f32,
d : u32,
}
var<pixel_local> P : PixelLocal;
struct FragmentInput {
@location(0) input : vec4f,
@builtin(position) pos : vec4f,
}
@fragment
fn F(fragmentInput : FragmentInput) -> @location(0) vec4f {
P.a += 42;
P.b -= 21;
P.c += 12.5f;
P.d -= 5;
return fragmentInput.input + fragmentInput.pos;
}
)";
auto* expect =
R"(
enable chromium_experimental_pixel_local;
@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32sint, read_write>;
@binding(2) @group(0) @internal(rov) var pixel_local_b : texture_storage_2d<r32float, read_write>;
@binding(3) @group(0) @internal(rov) var pixel_local_c : texture_storage_2d<r32uint, read_write>;
@binding(4) @group(0) @internal(rov) var pixel_local_d : texture_storage_2d<r32uint, read_write>;
fn load_from_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
P.a = bitcast<u32>(textureLoad(pixel_local_a, rov_texcoord).x);
P.b = bitcast<i32>(textureLoad(pixel_local_b, rov_texcoord).x);
P.c = bitcast<f32>(textureLoad(pixel_local_c, rov_texcoord).x);
P.d = textureLoad(pixel_local_d, rov_texcoord).x;
}
fn store_into_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
textureStore(pixel_local_a, rov_texcoord, vec4i(bitcast<i32>(P.a)));
textureStore(pixel_local_b, rov_texcoord, vec4f(bitcast<f32>(P.b)));
textureStore(pixel_local_c, rov_texcoord, vec4u(bitcast<u32>(P.c)));
textureStore(pixel_local_d, rov_texcoord, vec4u(P.d));
}
struct F_res {
@location(0)
output_0 : vec4<f32>,
}
@fragment
fn F(fragmentInput : FragmentInput) -> F_res {
let hlsl_sv_position = fragmentInput.pos;
load_from_pixel_local_storage(hlsl_sv_position);
let result = F_inner(fragmentInput);
store_into_pixel_local_storage(hlsl_sv_position);
return F_res(result);
}
struct PixelLocal {
a : u32,
b : i32,
c : f32,
d : u32,
}
var<private> P : PixelLocal;
struct FragmentInput {
@location(0)
input : vec4f,
@builtin(position)
pos : vec4f,
}
fn F_inner(fragmentInput : FragmentInput) -> vec4f {
P.a += 42;
P.b -= 21;
P.c += 12.5f;
P.d -= 5;
return (fragmentInput.input + fragmentInput.pos);
}
)";
auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Sint},
{1, 2, core::TexelFormat::kR32Float},
{2, 3, core::TexelFormat::kR32Uint},
{3, 4, core::TexelFormat::kR32Uint}}));
EXPECT_EQ(expect, str(got));
}
TEST_F(HLSLPixelLocalTest, UseInCallee) {
auto* src = R"(
enable chromium_experimental_pixel_local;
struct PixelLocal {
a : u32,
}
var<pixel_local> P : PixelLocal;
fn X() {
P.a += 42;
}
@fragment
fn F() {
X();
}
)";
auto* expect =
R"(
enable chromium_experimental_pixel_local;
@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
fn load_from_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
P.a = textureLoad(pixel_local_a, rov_texcoord).x;
}
fn store_into_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
}
@fragment
fn F(@builtin(position) my_pos : vec4<f32>) {
let hlsl_sv_position = my_pos;
load_from_pixel_local_storage(hlsl_sv_position);
F_inner();
store_into_pixel_local_storage(hlsl_sv_position);
}
struct PixelLocal {
a : u32,
}
var<private> P : PixelLocal;
fn X() {
P.a += 42;
}
fn F_inner() {
X();
}
)";
auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}));
EXPECT_EQ(expect, str(got));
}
TEST_F(HLSLPixelLocalTest, ROVLoadFunctionNameUsed) {
auto* src = R"(
enable chromium_experimental_pixel_local;
struct PixelLocal {
a : u32,
}
var<pixel_local> P : PixelLocal;
fn load_from_pixel_local_storage(my_input : vec4<f32>) {
P.a += u32(my_input.x);
}
@fragment
fn F() {
load_from_pixel_local_storage(vec4f(1.0, 0.0, 0.0, 1.0));
}
)";
auto* expect =
R"(
enable chromium_experimental_pixel_local;
@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
fn load_from_pixel_local_storage_1(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
P.a = textureLoad(pixel_local_a, rov_texcoord).x;
}
fn store_into_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
}
@fragment
fn F(@builtin(position) my_pos : vec4<f32>) {
let hlsl_sv_position = my_pos;
load_from_pixel_local_storage_1(hlsl_sv_position);
F_inner();
store_into_pixel_local_storage(hlsl_sv_position);
}
struct PixelLocal {
a : u32,
}
var<private> P : PixelLocal;
fn load_from_pixel_local_storage(my_input : vec4<f32>) {
P.a += u32(my_input.x);
}
fn F_inner() {
load_from_pixel_local_storage(vec4f(1.0, 0.0, 0.0, 1.0));
}
)";
auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}));
EXPECT_EQ(expect, str(got));
}
TEST_F(HLSLPixelLocalTest, ROVStoreFunctionNameUsed) {
auto* src = R"(
enable chromium_experimental_pixel_local;
struct PixelLocal {
a : u32,
}
var<pixel_local> P : PixelLocal;
fn store_into_pixel_local_storage(my_input : vec4<f32>) {
P.a += u32(my_input.x);
}
@fragment
fn F() {
store_into_pixel_local_storage(vec4f(1.0, 0.0, 0.0, 1.0));
}
)";
auto* expect =
R"(
enable chromium_experimental_pixel_local;
@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
fn load_from_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
P.a = textureLoad(pixel_local_a, rov_texcoord).x;
}
fn store_into_pixel_local_storage_1(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
}
@fragment
fn F(@builtin(position) my_pos : vec4<f32>) {
let hlsl_sv_position = my_pos;
load_from_pixel_local_storage(hlsl_sv_position);
F_inner();
store_into_pixel_local_storage_1(hlsl_sv_position);
}
struct PixelLocal {
a : u32,
}
var<private> P : PixelLocal;
fn store_into_pixel_local_storage(my_input : vec4<f32>) {
P.a += u32(my_input.x);
}
fn F_inner() {
store_into_pixel_local_storage(vec4f(1.0, 0.0, 0.0, 1.0));
}
)";
auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}));
EXPECT_EQ(expect, str(got));
}
TEST_F(HLSLPixelLocalTest, NewBuiltinPositionVariableNamesUsed) {
auto* src = R"(
enable chromium_experimental_pixel_local;
struct PixelLocal {
a : u32,
}
var<pixel_local> P : PixelLocal;
@fragment
fn F(@location(0) my_pos : vec4f) {
let hlsl_sv_position = my_pos * 2;
P.a += u32(hlsl_sv_position.y);
}
)";
auto* expect =
R"(
enable chromium_experimental_pixel_local;
@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
fn load_from_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
P.a = textureLoad(pixel_local_a, rov_texcoord).x;
}
fn store_into_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
}
@fragment
fn F(@location(0) my_pos : vec4f, @builtin(position) my_pos_1 : vec4<f32>) {
let hlsl_sv_position_1 = my_pos_1;
load_from_pixel_local_storage(hlsl_sv_position_1);
F_inner(my_pos);
store_into_pixel_local_storage(hlsl_sv_position_1);
}
struct PixelLocal {
a : u32,
}
var<private> P : PixelLocal;
fn F_inner(my_pos : vec4f) {
let hlsl_sv_position = (my_pos * 2);
P.a += u32(hlsl_sv_position.y);
}
)";
auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}));
EXPECT_EQ(expect, str(got));
}
TEST_F(HLSLPixelLocalTest, WithInvariantBuiltinInputParameter) {
auto* src = R"(
enable chromium_experimental_pixel_local;
struct PixelLocal {
a : u32,
}
var<pixel_local> P : PixelLocal;
@fragment
fn F(@invariant @builtin(position) pos : vec4f) {
P.a += u32(pos.x);
}
)";
auto* expect =
R"(
enable chromium_experimental_pixel_local;
@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
fn load_from_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
P.a = textureLoad(pixel_local_a, rov_texcoord).x;
}
fn store_into_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
}
@fragment
fn F(@invariant @builtin(position) pos : vec4f) {
let hlsl_sv_position = pos;
load_from_pixel_local_storage(hlsl_sv_position);
F_inner(pos);
store_into_pixel_local_storage(hlsl_sv_position);
}
struct PixelLocal {
a : u32,
}
var<private> P : PixelLocal;
fn F_inner(pos : vec4f) {
P.a += u32(pos.x);
}
)";
auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}));
EXPECT_EQ(expect, str(got));
}
TEST_F(HLSLPixelLocalTest, WithInvariantBuiltinInputStructParameter) {
auto* src = R"(
enable chromium_experimental_pixel_local;
struct PixelLocal {
a : u32,
}
var<pixel_local> P : PixelLocal;
struct In {
@invariant @builtin(position) pos : vec4f,
}
@fragment
fn F(in : In) {
P.a += u32(in.pos.x);
}
)";
auto* expect =
R"(
enable chromium_experimental_pixel_local;
@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
fn load_from_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
P.a = textureLoad(pixel_local_a, rov_texcoord).x;
}
fn store_into_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
}
@fragment
fn F(in : In) {
let hlsl_sv_position = in.pos;
load_from_pixel_local_storage(hlsl_sv_position);
F_inner(in);
store_into_pixel_local_storage(hlsl_sv_position);
}
struct PixelLocal {
a : u32,
}
var<private> P : PixelLocal;
struct In {
@invariant @builtin(position)
pos : vec4f,
}
fn F_inner(in : In) {
P.a += u32(in.pos.x);
}
)";
auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}));
EXPECT_EQ(expect, str(got));
}
TEST_F(HLSLPixelLocalTest, WithLocationInputParameter) {
auto* src = R"(
enable chromium_experimental_pixel_local;
struct PixelLocal {
a : u32,
}
var<pixel_local> P : PixelLocal;
@fragment
fn F(@location(0) a : vec4f, @interpolate(flat) @location(1) b : vec4f) {
P.a += u32(a.x) + u32(b.y);
}
)";
auto* expect =
R"(
enable chromium_experimental_pixel_local;
@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
fn load_from_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
P.a = textureLoad(pixel_local_a, rov_texcoord).x;
}
fn store_into_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
}
@fragment
fn F(@location(0) a : vec4f, @interpolate(flat) @location(1) b : vec4f, @builtin(position) my_pos : vec4<f32>) {
let hlsl_sv_position = my_pos;
load_from_pixel_local_storage(hlsl_sv_position);
F_inner(a, b);
store_into_pixel_local_storage(hlsl_sv_position);
}
struct PixelLocal {
a : u32,
}
var<private> P : PixelLocal;
fn F_inner(a : vec4f, b : vec4f) {
P.a += (u32(a.x) + u32(b.y));
}
)";
auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}));
EXPECT_EQ(expect, str(got));
}
TEST_F(HLSLPixelLocalTest, WithLocationInputStructParameter) {
auto* src = R"(
enable chromium_experimental_pixel_local;
struct PixelLocal {
a : u32,
}
var<pixel_local> P : PixelLocal;
struct In {
@location(0) a : vec4f,
@interpolate(flat) @location(1) b : vec4f,
}
@fragment
fn F(in : In) {
P.a += u32(in.a.x) + u32(in.b.y);
}
)";
auto* expect =
R"(
enable chromium_experimental_pixel_local;
@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
fn load_from_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
P.a = textureLoad(pixel_local_a, rov_texcoord).x;
}
fn store_into_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
}
@fragment
fn F(in : In, @builtin(position) my_pos : vec4<f32>) {
let hlsl_sv_position = my_pos;
load_from_pixel_local_storage(hlsl_sv_position);
F_inner(in);
store_into_pixel_local_storage(hlsl_sv_position);
}
struct PixelLocal {
a : u32,
}
var<private> P : PixelLocal;
struct In {
@location(0)
a : vec4f,
@interpolate(flat) @location(1)
b : vec4f,
}
fn F_inner(in : In) {
P.a += (u32(in.a.x) + u32(in.b.y));
}
)";
auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}));
EXPECT_EQ(expect, str(got));
}
TEST_F(HLSLPixelLocalTest, WithBuiltinAndLocationInputParameter) {
auto* src = R"(
enable chromium_experimental_pixel_local;
struct PixelLocal {
a : u32,
}
var<pixel_local> P : PixelLocal;
@fragment
fn F(@builtin(position) pos : vec4f, @location(0) uv : vec4f) {
P.a += u32(pos.x) + u32(uv.x);
}
)";
auto* expect =
R"(
enable chromium_experimental_pixel_local;
@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
fn load_from_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
P.a = textureLoad(pixel_local_a, rov_texcoord).x;
}
fn store_into_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
}
@fragment
fn F(@builtin(position) pos : vec4f, @location(0) uv : vec4f) {
let hlsl_sv_position = pos;
load_from_pixel_local_storage(hlsl_sv_position);
F_inner(pos, uv);
store_into_pixel_local_storage(hlsl_sv_position);
}
struct PixelLocal {
a : u32,
}
var<private> P : PixelLocal;
fn F_inner(pos : vec4f, uv : vec4f) {
P.a += (u32(pos.x) + u32(uv.x));
}
)";
auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}));
EXPECT_EQ(expect, str(got));
}
TEST_F(HLSLPixelLocalTest, WithBuiltinAndLocationInputStructParameter) {
auto* src = R"(
enable chromium_experimental_pixel_local;
struct PixelLocal {
a : u32,
}
var<pixel_local> P : PixelLocal;
struct In {
@builtin(position) pos : vec4f,
@location(0) uv : vec4f,
}
@fragment
fn F(in : In) {
P.a += u32(in.pos.x) + u32(in.uv.x);
}
)";
auto* expect =
R"(
enable chromium_experimental_pixel_local;
@binding(1) @group(0) @internal(rov) var pixel_local_a : texture_storage_2d<r32uint, read_write>;
fn load_from_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
P.a = textureLoad(pixel_local_a, rov_texcoord).x;
}
fn store_into_pixel_local_storage(my_input : vec4<f32>) {
let rov_texcoord = vec2u(my_input.xy);
textureStore(pixel_local_a, rov_texcoord, vec4u(P.a));
}
@fragment
fn F(in : In) {
let hlsl_sv_position = in.pos;
load_from_pixel_local_storage(hlsl_sv_position);
F_inner(in);
store_into_pixel_local_storage(hlsl_sv_position);
}
struct PixelLocal {
a : u32,
}
var<private> P : PixelLocal;
struct In {
@builtin(position)
pos : vec4f,
@location(0)
uv : vec4f,
}
fn F_inner(in : In) {
P.a += (u32(in.pos.x) + u32(in.uv.x));
}
)";
auto got = Run<PixelLocal>(src, Bindings({{0, 1, core::TexelFormat::kR32Uint}}));
EXPECT_EQ(expect, str(got));
}
} // namespace
} // namespace tint::hlsl::writer