From 3e464dcd7557531cc00588c4aec93fbf55c45294 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ari=20Suonp=C3=A4=C3=A4?= Date: Fri, 3 Apr 2020 13:28:59 +0300 Subject: [PATCH 1/7] Added depth and stencil support for Amber Script --- docs/amber_script.md | 51 ++ src/CMakeLists.txt | 2 + src/amberscript/parser.cc | 376 +++++++++++- src/amberscript/parser.h | 4 + src/amberscript/parser_bind_test.cc | 5 +- src/amberscript/parser_depth_test.cc | 557 +++++++++++++++++ src/amberscript/parser_pipeline_test.cc | 8 +- src/amberscript/parser_stencil_test.cc | 578 ++++++++++++++++++ src/buffer.h | 2 +- src/format.h | 8 + src/pipeline.cc | 38 +- src/pipeline.h | 29 +- src/pipeline_test.cc | 24 +- src/vkscript/parser.cc | 6 +- src/vulkan/device.cc | 2 +- src/vulkan/engine_vulkan.cc | 16 +- src/vulkan/frame_buffer.cc | 55 +- src/vulkan/frame_buffer.h | 10 +- src/vulkan/graphics_pipeline.cc | 72 +-- src/vulkan/graphics_pipeline.h | 6 +- src/vulkan/image_descriptor.cc | 19 +- src/vulkan/transfer_image.cc | 42 +- src/vulkan/transfer_image.h | 5 +- tests/cases/draw_rectangles_depth_test.amber | 136 +++++ .../cases/draw_rectangles_stencil_test.amber | 149 +++++ 25 files changed, 2049 insertions(+), 151 deletions(-) create mode 100644 src/amberscript/parser_depth_test.cc create mode 100644 src/amberscript/parser_stencil_test.cc create mode 100644 tests/cases/draw_rectangles_depth_test.amber create mode 100644 tests/cases/draw_rectangles_stencil_test.amber diff --git a/docs/amber_script.md b/docs/amber_script.md index 56430f716..81577c7fe 100644 --- a/docs/amber_script.md +++ b/docs/amber_script.md @@ -326,6 +326,57 @@ The following commands are all specified within the `PIPELINE` command. POLYGON_MODE {mode} ``` +#### Compare operations + * `never` + * `less` + * `equal` + * `less_or_equal` + * `greater` + * `not_equal` + * `greater_or_equal` + * `always` + +```groovy + # Set depth test settings. All enable options are specified with keywords on and off. + # BOUNDS and BIAS values are specified with decimal numbers. |compare_op| is selected + # from the list of compare operations above. + DEPTH + TEST {test_enable} + WRITE {write_enable} + COMPARE {compare_op} + CLAMP {clamp_enable} + BOUNDS min {bound_min} max {bounds_max} + BIAS constant {bias_constant} clamp {bias_clamp} slope {bias_slope} + END +``` + +#### Stencil operations + * `keep` + * `replace` + * `increment_and_clamp` + * `decrement_and_clamp` + * `invert` + * `increment_and_wrap` + * `decrement_and_wrap` + +```groovy + # Set stencil test settings. |face| can be front, back, or front_and_back. + # |test_enable| is either on or off and affects both faces. |fail_op|, |pass_op|, + # and |depth_fail_op| are selected from the stencil operations table above, + # and |compare_op| from the compare operations table. |compare_mask|, |write_mask|, + # and |reference| are 8bit unsigned integer values (range 0..255). + STENCIL {face} + TEST {test_enable} + FAIL {fail_op} + PASS {pass_op} + DEPTH_FAIL {depth_fail_op} + COMPARE {compare_op} + COMPARE_MASK {compare_mask} + WRITE_MASK {write_mask} + REFERENCE {reference} + END +``` + ```groovy # Set the size of the render buffers. |width| and |height| are integers and # default to 250x250. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a50c33c23..e297f3a69 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -135,6 +135,7 @@ if (${AMBER_ENABLE_TESTS}) amberscript/parser_compile_options_test.cc amberscript/parser_copy_test.cc amberscript/parser_device_feature_test.cc + amberscript/parser_depth_test.cc amberscript/parser_expect_test.cc amberscript/parser_extension_test.cc amberscript/parser_framebuffer_test.cc @@ -147,6 +148,7 @@ if (${AMBER_ENABLE_TESTS}) amberscript/parser_set_test.cc amberscript/parser_shader_opt_test.cc amberscript/parser_shader_test.cc + amberscript/parser_stencil_test.cc amberscript/parser_struct_test.cc amberscript/parser_test.cc buffer_test.cc diff --git a/src/amberscript/parser.cc b/src/amberscript/parser.cc index 60292b08c..3ebaffa0a 100644 --- a/src/amberscript/parser.cc +++ b/src/amberscript/parser.cc @@ -152,6 +152,26 @@ ImageDimension StrToImageDimension(const std::string& str) { return ImageDimension::kUnknown; } +std::map compare_ops = { + {"never", CompareOp::kNever}, + {"less", CompareOp::kLess}, + {"equal", CompareOp::kEqual}, + {"less_or_equal", CompareOp::kLessOrEqual}, + {"greater", CompareOp::kGreater}, + {"not_equal", CompareOp::kNotEqual}, + {"greater_or_equal", CompareOp::kGreaterOrEqual}, + {"always", CompareOp::kAlways}}; + +std::map stencil_ops = { + {"keep", StencilOp::kKeep}, + {"zero", StencilOp::kZero}, + {"replace", StencilOp::kReplace}, + {"increment_and_clamp", StencilOp::kIncrementAndClamp}, + {"decrement_and_clamp", StencilOp::kDecrementAndClamp}, + {"invert", StencilOp::kInvert}, + {"increment_and_wrap", StencilOp::kIncrementAndWrap}, + {"decrement_and_wrap", StencilOp::kDecrementAndWrap}}; + } // namespace Parser::Parser() : amber::Parser() {} @@ -241,8 +261,9 @@ Result Parser::Parse(const std::string& data) { } bool Parser::IsRepeatable(const std::string& name) const { - return name == "CLEAR" || name == "CLEAR_COLOR" || name == "COPY" || - name == "EXPECT" || name == "RUN" || name == "DEBUG"; + return name == "CLEAR" || name == "CLEAR_COLOR" || name == "CLEAR_DEPTH" || + name == "CLEAR_STENCIL" || name == "COPY" || name == "EXPECT" || + name == "RUN" || name == "DEBUG"; } // The given |name| must be one of the repeatable commands or this method @@ -250,6 +271,10 @@ bool Parser::IsRepeatable(const std::string& name) const { Result Parser::ParseRepeatableCommand(const std::string& name) { if (name == "CLEAR") return ParseClear(); + if (name == "CLEAR_DEPTH") + return ParseClearDepth(); + if (name == "CLEAR_STENCIL") + return ParseClearStencil(); if (name == "CLEAR_COLOR") return ParseClearColor(); if (name == "COPY") @@ -448,6 +473,10 @@ Result Parser::ParsePipelineBody(const std::string& cmd_name, r = ParsePipelineShaderCompileOptions(pipeline.get()); } else if (tok == "POLYGON_MODE") { r = ParsePipelinePolygonMode(pipeline.get()); + } else if (tok == "DEPTH") { + r = ParsePipelineDepth(pipeline.get()); + } else if (tok == "STENCIL") { + r = ParsePipelineStencil(pipeline.get()); } else { r = Result("unknown token in pipeline block: " + tok); } @@ -695,7 +724,7 @@ Result Parser::ToBufferType(const std::string& name, BufferType* type) { if (name == "color") *type = BufferType::kColor; else if (name == "depth_stencil") - *type = BufferType::kDepth; + *type = BufferType::kDepthStencil; else if (name == "push_constant") *type = BufferType::kPushConstant; else if (name == "combined_image_sampler") @@ -776,8 +805,8 @@ Result Parser::ParsePipelineBind(Pipeline* pipeline) { if (!r.IsSuccess()) return r; - } else if (buffer_type == BufferType::kDepth) { - r = pipeline->SetDepthBuffer(buffer); + } else if (buffer_type == BufferType::kDepthStencil) { + r = pipeline->SetDepthStencilBuffer(buffer); if (!r.IsSuccess()) return r; @@ -1058,17 +1087,274 @@ Result Parser::ParsePipelinePolygonMode(Pipeline* pipeline) { auto mode = token->AsString(); if (mode == "fill") - pipeline->SetPolygonMode(PolygonMode::kFill); + pipeline->GetPipelineData()->SetPolygonMode(PolygonMode::kFill); else if (mode == "line") - pipeline->SetPolygonMode(PolygonMode::kLine); + pipeline->GetPipelineData()->SetPolygonMode(PolygonMode::kLine); else if (mode == "point") - pipeline->SetPolygonMode(PolygonMode::kPoint); + pipeline->GetPipelineData()->SetPolygonMode(PolygonMode::kPoint); else return Result("invalid polygon mode: " + mode); return ValidateEndOfStatement("POLYGON_MODE command"); } +Result Parser::ParsePipelineDepth(Pipeline* pipeline) { + while (true) { + auto token = tokenizer_->NextToken(); + if (token->IsEOL()) + continue; + if (token->IsEOS()) + return Result("DEPTH missing END command"); + if (!token->IsIdentifier()) + return Result("DEPTH options must be identifiers"); + if (token->AsString() == "END") + break; + + if (token->AsString() == "TEST") { + token = tokenizer_->NextToken(); + + if (!token->IsIdentifier()) + return Result("invalid value for TEST"); + + if (token->AsString() == "on") + pipeline->GetPipelineData()->SetEnableDepthTest(true); + else if (token->AsString() == "off") + pipeline->GetPipelineData()->SetEnableDepthTest(false); + else + return Result("invalid value for TEST: " + token->AsString()); + } else if (token->AsString() == "CLAMP") { + token = tokenizer_->NextToken(); + + if (!token->IsIdentifier()) + return Result("invalid value for CLAMP"); + + if (token->AsString() == "on") + pipeline->GetPipelineData()->SetEnableDepthClamp(true); + else if (token->AsString() == "off") + pipeline->GetPipelineData()->SetEnableDepthClamp(false); + else + return Result("invalid value for CLAMP: " + token->AsString()); + } else if (token->AsString() == "WRITE") { + token = tokenizer_->NextToken(); + + if (!token->IsIdentifier()) + return Result("invalid value for WRITE"); + + if (token->AsString() == "on") + pipeline->GetPipelineData()->SetEnableDepthWrite(true); + else if (token->AsString() == "off") + pipeline->GetPipelineData()->SetEnableDepthWrite(false); + else + return Result("invalid value for WRITE: " + token->AsString()); + } else if (token->AsString() == "COMPARE") { + token = tokenizer_->NextToken(); + + if (!token->IsIdentifier()) + return Result("invalid value for COMPARE"); + + auto it = compare_ops.find(token->AsString()); + if (it != compare_ops.end()) { + pipeline->GetPipelineData()->SetDepthCompareOp(it->second); + } else { + return Result("invalid value for COMPARE: " + token->AsString()); + } + } else if (token->AsString() == "BOUNDS") { + token = tokenizer_->NextToken(); + if (!token->IsIdentifier() || token->AsString() != "min") + return Result("BOUNDS expecting min"); + + token = tokenizer_->NextToken(); + if (!token->IsDouble()) + return Result("BOUNDS invalid value for min"); + pipeline->GetPipelineData()->SetMinDepthBounds(token->AsFloat()); + + token = tokenizer_->NextToken(); + if (!token->IsIdentifier() || token->AsString() != "max") + return Result("BOUNDS expecting max"); + + token = tokenizer_->NextToken(); + if (!token->IsDouble()) + return Result("BOUNDS invalid value for max"); + pipeline->GetPipelineData()->SetMaxDepthBounds(token->AsFloat()); + } else if (token->AsString() == "BIAS") { + pipeline->GetPipelineData()->SetEnableDepthBias(true); + + token = tokenizer_->NextToken(); + if (!token->IsIdentifier() || token->AsString() != "constant") + return Result("BIAS expecting constant"); + + token = tokenizer_->NextToken(); + if (!token->IsDouble()) + return Result("BIAS invalid value for constant"); + pipeline->GetPipelineData()->SetDepthBiasConstantFactor(token->AsFloat()); + + token = tokenizer_->NextToken(); + if (!token->IsIdentifier() || token->AsString() != "clamp") + return Result("BIAS expecting clamp"); + + token = tokenizer_->NextToken(); + if (!token->IsDouble()) + return Result("BIAS invalid value for clamp"); + pipeline->GetPipelineData()->SetDepthBiasClamp(token->AsFloat()); + + token = tokenizer_->NextToken(); + if (!token->IsIdentifier() || token->AsString() != "slope") + return Result("BIAS expecting slope"); + + token = tokenizer_->NextToken(); + if (!token->IsDouble()) + return Result("BIAS invalid value for slope"); + pipeline->GetPipelineData()->SetDepthBiasSlopeFactor(token->AsFloat()); + } else { + return Result("invalid value for DEPTH: " + token->AsString()); + } + } + + return ValidateEndOfStatement("DEPTH command"); +} + +Result Parser::ParsePipelineStencil(Pipeline* pipeline) { + auto token = tokenizer_->NextToken(); + if (!token->IsIdentifier()) + return Result("STENCIL missing face"); + + bool setFront = false; + bool setBack = false; + + if (token->AsString() == "front") { + setFront = true; + } else if (token->AsString() == "back") { + setBack = true; + } else if (token->AsString() == "front_and_back") { + setFront = true; + setBack = true; + } else { + return Result("STENCIL invalid face: " + token->AsString()); + } + + while (true) { + token = tokenizer_->NextToken(); + if (token->IsEOL()) + continue; + if (token->IsEOS()) + return Result("STENCIL missing END command"); + if (!token->IsIdentifier()) + return Result("STENCIL options must be identifiers"); + if (token->AsString() == "END") + break; + + if (token->AsString() == "TEST") { + token = tokenizer_->NextToken(); + + if (!token->IsIdentifier()) + return Result("STENCIL invalid value for TEST"); + + if (token->AsString() == "on") + pipeline->GetPipelineData()->SetEnableStencilTest(true); + else if (token->AsString() == "off") + pipeline->GetPipelineData()->SetEnableStencilTest(false); + else + return Result("STENCIL invalid value for TEST: " + token->AsString()); + } else if (token->AsString() == "FAIL") { + token = tokenizer_->NextToken(); + + if (!token->IsIdentifier()) + return Result("STENCIL invalid value for FAIL"); + + auto it = stencil_ops.find(token->AsString()); + if (it != stencil_ops.end()) { + if (setFront) + pipeline->GetPipelineData()->SetFrontFailOp(it->second); + if (setBack) + pipeline->GetPipelineData()->SetBackFailOp(it->second); + } else { + return Result("STENCIL invalid value for FAIL: " + token->AsString()); + } + } else if (token->AsString() == "PASS") { + token = tokenizer_->NextToken(); + + if (!token->IsIdentifier()) + return Result("STENCIL invalid value for PASS"); + + auto it = stencil_ops.find(token->AsString()); + if (it != stencil_ops.end()) { + if (setFront) + pipeline->GetPipelineData()->SetFrontPassOp(it->second); + if (setBack) + pipeline->GetPipelineData()->SetBackPassOp(it->second); + } else { + return Result("STENCIL invalid value for PASS: " + token->AsString()); + } + } else if (token->AsString() == "DEPTH_FAIL") { + token = tokenizer_->NextToken(); + + if (!token->IsIdentifier()) + return Result("STENCIL invalid value for DEPTH_FAIL"); + + auto it = stencil_ops.find(token->AsString()); + if (it != stencil_ops.end()) { + if (setFront) + pipeline->GetPipelineData()->SetFrontDepthFailOp(it->second); + if (setBack) + pipeline->GetPipelineData()->SetBackDepthFailOp(it->second); + } else { + return Result("STENCIL invalid value for DEPTH_FAIL: " + + token->AsString()); + } + } else if (token->AsString() == "COMPARE") { + token = tokenizer_->NextToken(); + + if (!token->IsIdentifier()) + return Result("STENCIL invalid value for COMPARE"); + + auto it = compare_ops.find(token->AsString()); + if (it != compare_ops.end()) { + if (setFront) + pipeline->GetPipelineData()->SetFrontCompareOp(it->second); + if (setBack) + pipeline->GetPipelineData()->SetBackCompareOp(it->second); + } else { + return Result("STENCIL invalid value for COMPARE: " + + token->AsString()); + } + } else if (token->AsString() == "COMPARE_MASK") { + token = tokenizer_->NextToken(); + + if (!token->IsInteger()) + return Result("STENCIL invalid value for COMPARE_MASK"); + + if (setFront) + pipeline->GetPipelineData()->SetFrontCompareMask(token->AsUint32()); + if (setBack) + pipeline->GetPipelineData()->SetBackCompareMask(token->AsUint32()); + } else if (token->AsString() == "WRITE_MASK") { + token = tokenizer_->NextToken(); + + if (!token->IsInteger()) + return Result("STENCIL invalid value for WRITE_MASK"); + + if (setFront) + pipeline->GetPipelineData()->SetFrontWriteMask(token->AsUint32()); + if (setBack) + pipeline->GetPipelineData()->SetBackWriteMask(token->AsUint32()); + } else if (token->AsString() == "REFERENCE") { + token = tokenizer_->NextToken(); + + if (!token->IsInteger()) + return Result("STENCIL invalid value for REFERENCE"); + + if (setFront) + pipeline->GetPipelineData()->SetFrontReference(token->AsUint32()); + if (setBack) + pipeline->GetPipelineData()->SetBackReference(token->AsUint32()); + } else { + return Result("STENCIL invalid value for STENCIL: " + token->AsString()); + } + } + + return ValidateEndOfStatement("STENCIL command"); +} + Result Parser::ParseStruct() { auto token = tokenizer_->NextToken(); if (!token->IsIdentifier()) @@ -1710,10 +1996,10 @@ Result Parser::ParseRun() { if (!token->IsInteger()) return Result("missing X position for RUN command"); - auto cmd = MakeUnique(pipeline, PipelineData{}); + auto cmd = + MakeUnique(pipeline, *pipeline->GetPipelineData()); cmd->SetLine(line); cmd->EnableOrtho(); - cmd->SetPolygonMode(pipeline->GetPolygonMode()); Result r = token->ConvertToDouble(); if (!r.IsSuccess()) @@ -1782,7 +2068,7 @@ Result Parser::ParseRun() { auto cmd = MakeUnique(pipeline); cmd->SetLine(line); - cmd->SetPolygonMode(pipeline->GetPolygonMode()); + cmd->SetPolygonMode(pipeline->GetPipelineData()->GetPolygonMode()); Result r = token->ConvertToDouble(); if (!r.IsSuccess()) @@ -1924,12 +2210,12 @@ Result Parser::ParseRun() { return Result("START_IDX plus COUNT exceeds vertex buffer data size"); } - auto cmd = MakeUnique(pipeline, PipelineData{}); + auto cmd = + MakeUnique(pipeline, *pipeline->GetPipelineData()); cmd->SetLine(line); cmd->SetTopology(topo); cmd->SetFirstVertexIndex(start_idx); cmd->SetVertexCount(count); - cmd->SetPolygonMode(pipeline->GetPolygonMode()); if (indexed) cmd->EnableIndexed(); @@ -2590,6 +2876,70 @@ Result Parser::ParseClearColor() { return ValidateEndOfStatement("CLEAR_COLOR command"); } +Result Parser::ParseClearDepth() { + auto token = tokenizer_->NextToken(); + if (!token->IsIdentifier()) + return Result("missing pipeline name for CLEAR_DEPTH command"); + + size_t line = tokenizer_->GetCurrentLine(); + + auto* pipeline = script_->GetPipeline(token->AsString()); + if (!pipeline) { + return Result("unknown pipeline for CLEAR_DEPTH command: " + + token->AsString()); + } + if (!pipeline->IsGraphics()) { + return Result("CLEAR_DEPTH command requires graphics pipeline"); + } + + auto cmd = MakeUnique(pipeline); + cmd->SetLine(line); + + token = tokenizer_->NextToken(); + if (token->IsEOL() || token->IsEOS()) + return Result("missing value for CLEAR_DEPTH command"); + if (!token->IsDouble()) { + return Result("invalid value for CLEAR_DEPTH command: " + + token->ToOriginalString()); + } + cmd->SetValue(token->AsFloat()); + + command_list_.push_back(std::move(cmd)); + return ValidateEndOfStatement("CLEAR_DEPTH command"); +} + +Result Parser::ParseClearStencil() { + auto token = tokenizer_->NextToken(); + if (!token->IsIdentifier()) + return Result("missing pipeline name for CLEAR_STENCIL command"); + + size_t line = tokenizer_->GetCurrentLine(); + + auto* pipeline = script_->GetPipeline(token->AsString()); + if (!pipeline) { + return Result("unknown pipeline for CLEAR_STENCIL command: " + + token->AsString()); + } + if (!pipeline->IsGraphics()) { + return Result("CLEAR_STENCIL command requires graphics pipeline"); + } + + auto cmd = MakeUnique(pipeline); + cmd->SetLine(line); + + token = tokenizer_->NextToken(); + if (token->IsEOL() || token->IsEOS()) + return Result("missing value for CLEAR_STENCIL command"); + if (!token->IsInteger()) { + return Result("invalid value for CLEAR_STENCIL command: " + + token->ToOriginalString()); + } + cmd->SetValue(token->AsUint32()); + + command_list_.push_back(std::move(cmd)); + return ValidateEndOfStatement("CLEAR_STENCIL command"); +} + Result Parser::ParseDeviceFeature() { auto token = tokenizer_->NextToken(); if (token->IsEOS() || token->IsEOL()) diff --git a/src/amberscript/parser.h b/src/amberscript/parser.h index 8f62e9014..9bbd703a6 100644 --- a/src/amberscript/parser.h +++ b/src/amberscript/parser.h @@ -67,11 +67,15 @@ class Parser : public amber::Parser { Result ParsePipelineIndexData(Pipeline*); Result ParsePipelineSet(Pipeline*); Result ParsePipelinePolygonMode(Pipeline*); + Result ParsePipelineDepth(Pipeline*); + Result ParsePipelineStencil(Pipeline*); Result ParseRun(); Result ParseDebug(); Result ParseDebugThread(debug::Events*); Result ParseDebugThreadBody(debug::Thread* thread); Result ParseClear(); + Result ParseClearDepth(); + Result ParseClearStencil(); Result ParseClearColor(); Result ParseExpect(); Result ParseCopy(); diff --git a/src/amberscript/parser_bind_test.cc b/src/amberscript/parser_bind_test.cc index 0adbacbe9..f027b7065 100644 --- a/src/amberscript/parser_bind_test.cc +++ b/src/amberscript/parser_bind_test.cc @@ -513,7 +513,7 @@ END)"; ASSERT_EQ(1U, pipelines.size()); const auto* pipeline = pipelines[0].get(); - const auto& buf = pipeline->GetDepthBuffer(); + const auto& buf = pipeline->GetDepthStencilBuffer(); ASSERT_TRUE(buf.buffer != nullptr); EXPECT_EQ(90 * 180, buf.buffer->ElementCount()); EXPECT_EQ(90 * 180 * 4, buf.buffer->ValueCount()); @@ -649,7 +649,8 @@ END)"; Parser parser; Result r = parser.Parse(in); ASSERT_FALSE(r.IsSuccess()); - EXPECT_EQ("14: can only bind one depth buffer in a PIPELINE", r.Error()); + EXPECT_EQ("14: can only bind one depth/stencil buffer in a PIPELINE", + r.Error()); } TEST_F(AmberScriptParserTest, BindVertexData) { diff --git a/src/amberscript/parser_depth_test.cc b/src/amberscript/parser_depth_test.cc new file mode 100644 index 000000000..944fb8439 --- /dev/null +++ b/src/amberscript/parser_depth_test.cc @@ -0,0 +1,557 @@ +// Copyright 2020 The Amber 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 parseried. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "gtest/gtest.h" +#include "src/amberscript/parser.h" + +namespace amber { +namespace amberscript { + +using AmberScriptParserTest = testing::Test; + +TEST_F(AmberScriptParserTest, DepthAllValues) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + DEPTH + TEST on + WRITE on + COMPARE less_or_equal + CLAMP on + BOUNDS min 1.5 max 6.7 + BIAS constant 2.1 clamp 3.5 slope 5.5 + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_TRUE(r.IsSuccess()) << r.Error(); + + auto script = parser.GetScript(); + const auto& pipelines = script->GetPipelines(); + ASSERT_EQ(1U, pipelines.size()); + + auto* pipeline = pipelines[0].get(); + ASSERT_NE(nullptr, pipeline->GetDepthStencilBuffer().buffer); + + ASSERT_TRUE(pipeline->GetPipelineData()->GetEnableDepthTest()); + ASSERT_TRUE(pipeline->GetPipelineData()->GetEnableDepthWrite()); + ASSERT_TRUE(pipeline->GetPipelineData()->GetEnableDepthClamp()); + ASSERT_FLOAT_EQ(1.5, pipeline->GetPipelineData()->GetMinDepthBounds()); + ASSERT_FLOAT_EQ(6.7, pipeline->GetPipelineData()->GetMaxDepthBounds()); + ASSERT_FLOAT_EQ(2.1, + pipeline->GetPipelineData()->GetDepthBiasConstantFactor()); + ASSERT_FLOAT_EQ(3.5, pipeline->GetPipelineData()->GetDepthBiasClamp()); + ASSERT_FLOAT_EQ(5.5, pipeline->GetPipelineData()->GetDepthBiasSlopeFactor()); +} + +TEST_F(AmberScriptParserTest, DepthTestMissingValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + DEPTH + TEST + WRITE on + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("17: invalid value for TEST", r.Error()); +} + +TEST_F(AmberScriptParserTest, DepthTestInvalidValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + DEPTH + TEST foo + WRITE on + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("16: invalid value for TEST: foo", r.Error()); +} + +TEST_F(AmberScriptParserTest, DepthWriteMissingValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + DEPTH + TEST on + WRITE + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("18: invalid value for WRITE", r.Error()); +} + +TEST_F(AmberScriptParserTest, DepthWriteInvalidValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + DEPTH + TEST on + WRITE foo + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("17: invalid value for WRITE: foo", r.Error()); +} + +TEST_F(AmberScriptParserTest, DepthClampMissingValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + DEPTH + TEST on + CLAMP + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("18: invalid value for CLAMP", r.Error()); +} + +TEST_F(AmberScriptParserTest, DepthClampInvalidValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + DEPTH + TEST on + CLAMP foo + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("17: invalid value for CLAMP: foo", r.Error()); +} + +TEST_F(AmberScriptParserTest, DepthCompareMissingValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + DEPTH + TEST on + COMPARE + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("18: invalid value for COMPARE", r.Error()); +} + +TEST_F(AmberScriptParserTest, DepthCompareInvalidValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + DEPTH + TEST on + COMPARE foo + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("17: invalid value for COMPARE: foo", r.Error()); +} + +TEST_F(AmberScriptParserTest, DepthBoundsExpectingMin) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + DEPTH + TEST on + BOUNDS + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("18: BOUNDS expecting min", r.Error()); +} + +TEST_F(AmberScriptParserTest, DepthBoundsMinInvalidValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + DEPTH + TEST on + BOUNDS min foo + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("17: BOUNDS invalid value for min", r.Error()); +} + +TEST_F(AmberScriptParserTest, DepthBoundsExpectingMax) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + DEPTH + TEST on + BOUNDS min 0.0 foo + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("17: BOUNDS expecting max", r.Error()); +} + +TEST_F(AmberScriptParserTest, DepthBoundsMaxInvalidValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + DEPTH + TEST on + BOUNDS min 0.0 max foo + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("17: BOUNDS invalid value for max", r.Error()); +} + +TEST_F(AmberScriptParserTest, DepthBiasExpectingConstant) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + DEPTH + TEST on + BIAS + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("18: BIAS expecting constant", r.Error()); +} + +TEST_F(AmberScriptParserTest, DepthBiasConstantInvalidValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + DEPTH + TEST on + BIAS constant foo + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("17: BIAS invalid value for constant", r.Error()); +} + +TEST_F(AmberScriptParserTest, DepthBiasExpectingClamp) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + DEPTH + TEST on + BIAS constant 0.0 foo + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("17: BIAS expecting clamp", r.Error()); +} + +TEST_F(AmberScriptParserTest, DepthBiasClampInvalidValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + DEPTH + TEST on + BIAS constant 0.0 clamp foo + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("17: BIAS invalid value for clamp", r.Error()); +} + +TEST_F(AmberScriptParserTest, DepthBiasExpectingSlope) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + DEPTH + TEST on + BIAS constant 0.0 clamp 0.0 + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("18: BIAS expecting slope", r.Error()); +} + +TEST_F(AmberScriptParserTest, DepthBiasSlopeInvalidValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + DEPTH + TEST on + BIAS constant 0.0 clamp 0.0 slope foo + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("17: BIAS invalid value for slope", r.Error()); +} + +} // namespace amberscript +} // namespace amber diff --git a/src/amberscript/parser_pipeline_test.cc b/src/amberscript/parser_pipeline_test.cc index 3e2922b51..197f1a198 100644 --- a/src/amberscript/parser_pipeline_test.cc +++ b/src/amberscript/parser_pipeline_test.cc @@ -279,13 +279,13 @@ END)"; const auto& pipelines = script->GetPipelines(); ASSERT_EQ(4U, pipelines.size()); - auto mode0 = pipelines[0]->GetPolygonMode(); + auto mode0 = pipelines[0]->GetPipelineData()->GetPolygonMode(); ASSERT_EQ(mode0, PolygonMode::kFill); - auto mode1 = pipelines[1]->GetPolygonMode(); + auto mode1 = pipelines[1]->GetPipelineData()->GetPolygonMode(); ASSERT_EQ(mode1, PolygonMode::kFill); - auto mode2 = pipelines[2]->GetPolygonMode(); + auto mode2 = pipelines[2]->GetPipelineData()->GetPolygonMode(); ASSERT_EQ(mode2, PolygonMode::kLine); - auto mode3 = pipelines[3]->GetPolygonMode(); + auto mode3 = pipelines[3]->GetPipelineData()->GetPolygonMode(); ASSERT_EQ(mode3, PolygonMode::kPoint); } diff --git a/src/amberscript/parser_stencil_test.cc b/src/amberscript/parser_stencil_test.cc new file mode 100644 index 000000000..d8cc89582 --- /dev/null +++ b/src/amberscript/parser_stencil_test.cc @@ -0,0 +1,578 @@ +// Copyright 2020 The Amber 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 parseried. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "gtest/gtest.h" +#include "src/amberscript/parser.h" + +namespace amber { +namespace amberscript { + +using AmberScriptParserTest = testing::Test; + +TEST_F(AmberScriptParserTest, StencilAllValues) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + STENCIL front + TEST on + FAIL increment_and_clamp + PASS invert + DEPTH_FAIL keep + COMPARE equal + COMPARE_MASK 1 + WRITE_MASK 2 + REFERENCE 3 + END + STENCIL back + TEST on + FAIL zero + PASS increment_and_wrap + DEPTH_FAIL replace + COMPARE greater + COMPARE_MASK 4 + WRITE_MASK 5 + REFERENCE 6 + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_TRUE(r.IsSuccess()) << r.Error(); + + auto script = parser.GetScript(); + const auto& pipelines = script->GetPipelines(); + ASSERT_EQ(1U, pipelines.size()); + + auto* pipeline = pipelines[0].get(); + ASSERT_NE(nullptr, pipeline->GetDepthStencilBuffer().buffer); + + ASSERT_TRUE(pipeline->GetPipelineData()->GetEnableStencilTest()); + ASSERT_EQ(StencilOp::kIncrementAndClamp, + pipeline->GetPipelineData()->GetFrontFailOp()); + ASSERT_EQ(StencilOp::kZero, pipeline->GetPipelineData()->GetBackFailOp()); + ASSERT_EQ(StencilOp::kInvert, pipeline->GetPipelineData()->GetFrontPassOp()); + ASSERT_EQ(StencilOp::kIncrementAndWrap, + pipeline->GetPipelineData()->GetBackPassOp()); + ASSERT_EQ(StencilOp::kKeep, + pipeline->GetPipelineData()->GetFrontDepthFailOp()); + ASSERT_EQ(StencilOp::kReplace, + pipeline->GetPipelineData()->GetBackDepthFailOp()); + ASSERT_EQ(CompareOp::kEqual, + pipeline->GetPipelineData()->GetFrontCompareOp()); + ASSERT_EQ(CompareOp::kGreater, + pipeline->GetPipelineData()->GetBackCompareOp()); + + ASSERT_EQ(1, pipeline->GetPipelineData()->GetFrontCompareMask()); + ASSERT_EQ(4, pipeline->GetPipelineData()->GetBackCompareMask()); + ASSERT_EQ(2, pipeline->GetPipelineData()->GetFrontWriteMask()); + ASSERT_EQ(5, pipeline->GetPipelineData()->GetBackWriteMask()); + ASSERT_EQ(3, pipeline->GetPipelineData()->GetFrontReference()); + ASSERT_EQ(6, pipeline->GetPipelineData()->GetBackReference()); +} + +TEST_F(AmberScriptParserTest, StencilMissingFace) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + STENCIL + TEST on + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("16: STENCIL missing face", r.Error()); +} + +TEST_F(AmberScriptParserTest, StencilInvalidFaceValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + STENCIL foo + TEST on + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("15: STENCIL invalid face: foo", r.Error()); +} + +TEST_F(AmberScriptParserTest, StencilTestMissingValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + STENCIL front + TEST + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("17: STENCIL invalid value for TEST", r.Error()); +} + +TEST_F(AmberScriptParserTest, StencilTestInvalidValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + STENCIL front + TEST foo + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("16: STENCIL invalid value for TEST: foo", r.Error()); +} + +TEST_F(AmberScriptParserTest, StencilFailMissingValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + STENCIL front + TEST on + FAIL + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("18: STENCIL invalid value for FAIL", r.Error()); +} + +TEST_F(AmberScriptParserTest, StencilFailInvalidValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + STENCIL front + TEST on + FAIL foo + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("17: STENCIL invalid value for FAIL: foo", r.Error()); +} + +TEST_F(AmberScriptParserTest, StencilPassMissingValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + STENCIL front + TEST on + PASS + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("18: STENCIL invalid value for PASS", r.Error()); +} + +TEST_F(AmberScriptParserTest, StencilPassInvalidValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + STENCIL front + TEST on + PASS foo + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("17: STENCIL invalid value for PASS: foo", r.Error()); +} + +TEST_F(AmberScriptParserTest, StencilDepthFailMissingValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + STENCIL front + TEST on + DEPTH_FAIL + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("18: STENCIL invalid value for DEPTH_FAIL", r.Error()); +} + +TEST_F(AmberScriptParserTest, StencilDepthFailInvalidValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + STENCIL front + TEST on + DEPTH_FAIL foo + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("17: STENCIL invalid value for DEPTH_FAIL: foo", r.Error()); +} + +TEST_F(AmberScriptParserTest, StencilCompareMissingValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + STENCIL front + TEST on + COMPARE + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("18: STENCIL invalid value for COMPARE", r.Error()); +} + +TEST_F(AmberScriptParserTest, StencilCompareInvalidValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + STENCIL front + TEST on + COMPARE foo + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("17: STENCIL invalid value for COMPARE: foo", r.Error()); +} + +TEST_F(AmberScriptParserTest, StencilCompareMaskMissingValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + STENCIL front + TEST on + COMPARE_MASK + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("18: STENCIL invalid value for COMPARE_MASK", r.Error()); +} + +TEST_F(AmberScriptParserTest, StencilCompareMaskInvalidValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + STENCIL front + TEST on + COMPARE_MASK foo + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("17: STENCIL invalid value for COMPARE_MASK", r.Error()); +} + +TEST_F(AmberScriptParserTest, StencilWriteMaskMissingValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + STENCIL front + TEST on + WRITE_MASK + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("18: STENCIL invalid value for WRITE_MASK", r.Error()); +} + +TEST_F(AmberScriptParserTest, StencilWriteMaskInvalidValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + STENCIL front + TEST on + WRITE_MASK foo + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("17: STENCIL invalid value for WRITE_MASK", r.Error()); +} + +TEST_F(AmberScriptParserTest, StencilReferenceMissingValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + STENCIL front + TEST on + REFERENCE + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("18: STENCIL invalid value for REFERENCE", r.Error()); +} + +TEST_F(AmberScriptParserTest, StencilReferenceInvalidValue) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT +BUFFER my_ds FORMAT D32_SFLOAT_S8_UINT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + BIND BUFFER my_fb AS color LOCATION 0 + BIND BUFFER my_ds AS depth_stencil + + STENCIL front + TEST on + REFERENCE foo + END +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()) << r.Error(); + EXPECT_EQ("17: STENCIL invalid value for REFERENCE", r.Error()); +} + +} // namespace amberscript +} // namespace amber diff --git a/src/buffer.h b/src/buffer.h index 9d6f3d6e0..82d77050d 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -37,7 +37,7 @@ enum class BufferType : int8_t { /// A color buffer. kColor = 0, /// A depth/stencil buffer. - kDepth, + kDepthStencil, /// An index buffer. kIndex, /// A sampled image. diff --git a/src/format.h b/src/format.h index e6e68ba59..bfef06d53 100644 --- a/src/format.h +++ b/src/format.h @@ -114,6 +114,14 @@ class Format { uint32_t SizeInBytes() const; bool IsFormatKnown() const { return format_type_ != FormatType::kUnknown; } + bool HasDepthComponent() const { + return format_type_ == FormatType::kD16_UNORM || + format_type_ == FormatType::kD16_UNORM_S8_UINT || + format_type_ == FormatType::kD24_UNORM_S8_UINT || + format_type_ == FormatType::kD32_SFLOAT || + format_type_ == FormatType::kD32_SFLOAT_S8_UINT || + format_type_ == FormatType::kX8_D24_UNORM_PACK32; + } bool HasStencilComponent() const { return format_type_ == FormatType::kD24_UNORM_S8_UINT || format_type_ == FormatType::kD16_UNORM_S8_UINT || diff --git a/src/pipeline.cc b/src/pipeline.cc index bebaf79a0..d7fff19fc 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -65,11 +65,12 @@ std::unique_ptr Pipeline::Clone() const { clone->color_attachments_ = color_attachments_; clone->vertex_buffers_ = vertex_buffers_; clone->buffers_ = buffers_; - clone->depth_buffer_ = depth_buffer_; + clone->depth_stencil_buffer_ = depth_stencil_buffer_; clone->index_buffer_ = index_buffer_; clone->fb_width_ = fb_width_; clone->fb_height_ = fb_height_; clone->set_arg_values_ = set_arg_values_; + clone->pipeline_data_ = pipeline_data_; if (!opencl_pod_buffers_.empty()) { // Generate specific buffers for the clone. @@ -184,16 +185,6 @@ Result Pipeline::SetShaderType(const Shader* shader, ShaderType type) { shader->GetName()); } -Result Pipeline::SetPolygonMode(PolygonMode mode) { - if (mode != PolygonMode::kFill && mode != PolygonMode::kLine && - mode != PolygonMode::kPoint) - return Result("invalid polygon mode specified for pipeline"); - - polygon_mode_ = mode; - - return {}; -} - Result Pipeline::Validate() const { for (const auto& attachment : color_attachments_) { if (attachment.buffer->ElementCount() != @@ -204,8 +195,8 @@ Result Pipeline::Validate() const { } } - if (depth_buffer_.buffer && - depth_buffer_.buffer->ElementCount() != fb_width_ * fb_height_) { + if (depth_stencil_buffer_.buffer && + depth_stencil_buffer_.buffer->ElementCount() != fb_width_ * fb_height_) { return Result("shared depth buffer must have same size over all PIPELINES"); } @@ -280,10 +271,10 @@ void Pipeline::UpdateFramebufferSizes() { attachment.buffer->SetElementCount(mip0_width * mip0_height); } - if (depth_buffer_.buffer) { - depth_buffer_.buffer->SetWidth(fb_width_); - depth_buffer_.buffer->SetHeight(fb_height_); - depth_buffer_.buffer->SetElementCount(size); + if (depth_stencil_buffer_.buffer) { + depth_stencil_buffer_.buffer->SetWidth(fb_width_); + depth_stencil_buffer_.buffer->SetHeight(fb_height_); + depth_stencil_buffer_.buffer->SetElementCount(size); } } @@ -323,12 +314,12 @@ Result Pipeline::GetLocationForColorAttachment(Buffer* buf, return Result("Unable to find requested buffer"); } -Result Pipeline::SetDepthBuffer(Buffer* buf) { - if (depth_buffer_.buffer != nullptr) - return Result("can only bind one depth buffer in a PIPELINE"); +Result Pipeline::SetDepthStencilBuffer(Buffer* buf) { + if (depth_stencil_buffer_.buffer != nullptr) + return Result("can only bind one depth/stencil buffer in a PIPELINE"); - depth_buffer_.buffer = buf; - depth_buffer_.type = BufferType::kDepth; + depth_stencil_buffer_.buffer = buf; + depth_stencil_buffer_.type = BufferType::kDepthStencil; buf->SetWidth(fb_width_); buf->SetHeight(fb_height_); @@ -381,7 +372,8 @@ std::unique_ptr Pipeline::GenerateDefaultColorAttachmentBuffer() { return buf; } -std::unique_ptr Pipeline::GenerateDefaultDepthAttachmentBuffer() { +std::unique_ptr +Pipeline::GenerateDefaultDepthStencilAttachmentBuffer() { TypeParser parser; auto type = parser.Parse(kDefaultDepthBufferFormat); auto fmt = MakeUnique(type.get()); diff --git a/src/pipeline.h b/src/pipeline.h index b565eca62..6302a32c4 100644 --- a/src/pipeline.h +++ b/src/pipeline.h @@ -25,6 +25,7 @@ #include "amber/result.h" #include "src/buffer.h" #include "src/command_data.h" +#include "src/pipeline_data.h" #include "src/sampler.h" #include "src/shader.h" @@ -244,11 +245,17 @@ class Pipeline { /// something goes wrong. Result GetLocationForColorAttachment(Buffer* buf, uint32_t* loc) const; - /// Sets |buf| as the depth buffer for this pipeline. - Result SetDepthBuffer(Buffer* buf); - /// Returns information on the depth buffer bound to the pipeline. If no - /// depth buffer is bound the |BufferInfo::buffer| parameter will be nullptr. - const BufferInfo& GetDepthBuffer() const { return depth_buffer_; } + /// Sets |buf| as the depth/stencil buffer for this pipeline. + Result SetDepthStencilBuffer(Buffer* buf); + /// Returns information on the depth/stencil buffer bound to the pipeline. If + /// no depth buffer is bound the |BufferInfo::buffer| parameter will be + /// nullptr. + const BufferInfo& GetDepthStencilBuffer() const { + return depth_stencil_buffer_; + } + + /// Returns pipeline data. + PipelineData* GetPipelineData() { return &pipeline_data_; } /// Returns information on all vertex buffers bound to the pipeline. const std::vector& GetVertexBuffers() const { @@ -305,16 +312,13 @@ class Pipeline { return push_constant_buffer_; } - Result SetPolygonMode(PolygonMode mode); - PolygonMode GetPolygonMode() const { return polygon_mode_; } - /// Validates that the pipeline has been created correctly. Result Validate() const; /// Generates a default color attachment in B8G8R8A8_UNORM. std::unique_ptr GenerateDefaultColorAttachmentBuffer(); - /// Generates a default depth attachment in D32_SFLOAT_S8_UINT format. - std::unique_ptr GenerateDefaultDepthAttachmentBuffer(); + /// Generates a default depth/stencil attachment in D32_SFLOAT_S8_UINT format. + std::unique_ptr GenerateDefaultDepthStencilAttachmentBuffer(); /// Information on values set for OpenCL-C plain-old-data args. struct ArgSetInfo { @@ -356,11 +360,10 @@ class Pipeline { std::vector> types_; std::vector samplers_; std::vector> formats_; - BufferInfo depth_buffer_; + BufferInfo depth_stencil_buffer_; BufferInfo push_constant_buffer_; Buffer* index_buffer_ = nullptr; - PolygonMode polygon_mode_ = PolygonMode::kFill; - + PipelineData pipeline_data_; uint32_t fb_width_ = 250; uint32_t fb_height_ = 250; diff --git a/src/pipeline_test.cc b/src/pipeline_test.cc index de7736996..f870bfce1 100644 --- a/src/pipeline_test.cc +++ b/src/pipeline_test.cc @@ -31,7 +31,7 @@ class PipelineTest : public testing::Test { public: void TearDown() override { color_buffer_ = nullptr; - depth_buffer_ = nullptr; + depth_stencil_buffer_ = nullptr; } void SetupColorAttachment(Pipeline* p, uint32_t location) { @@ -41,16 +41,16 @@ class PipelineTest : public testing::Test { p->AddColorAttachment(color_buffer_.get(), location, 0); } - void SetupDepthAttachment(Pipeline* p) { - if (!depth_buffer_) - depth_buffer_ = p->GenerateDefaultDepthAttachmentBuffer(); + void SetupDepthStencilAttachment(Pipeline* p) { + if (!depth_stencil_buffer_) + depth_stencil_buffer_ = p->GenerateDefaultDepthStencilAttachmentBuffer(); - p->SetDepthBuffer(depth_buffer_.get()); + p->SetDepthStencilBuffer(depth_stencil_buffer_.get()); } private: std::unique_ptr color_buffer_; - std::unique_ptr depth_buffer_; + std::unique_ptr depth_stencil_buffer_; }; TEST_F(PipelineTest, AddShader) { @@ -185,7 +185,7 @@ TEST_F(PipelineTest, SetOptimizationForInvalidShader) { TEST_F(PipelineTest, GraphicsPipelineRequiresColorAttachment) { Pipeline p(PipelineType::kGraphics); - SetupDepthAttachment(&p); + SetupDepthStencilAttachment(&p); Result r = p.Validate(); ASSERT_FALSE(r.IsSuccess()); @@ -199,7 +199,7 @@ TEST_F(PipelineTest, GraphicsPipelineRequiresVertexAndFragmentShader) { Pipeline p(PipelineType::kGraphics); SetupColorAttachment(&p, 0); - SetupDepthAttachment(&p); + SetupDepthStencilAttachment(&p); Result r = p.AddShader(&v, kShaderTypeVertex); EXPECT_TRUE(r.IsSuccess()) << r.Error(); @@ -220,7 +220,7 @@ TEST_F(PipelineTest, GraphicsPipelineMissingVertexShader) { Pipeline p(PipelineType::kGraphics); SetupColorAttachment(&p, 0); - SetupDepthAttachment(&p); + SetupDepthStencilAttachment(&p); Result r = p.AddShader(&g, kShaderTypeGeometry); EXPECT_TRUE(r.IsSuccess()) << r.Error(); @@ -238,7 +238,7 @@ TEST_F(PipelineTest, ComputePipelineRequiresComputeShader) { Pipeline p(PipelineType::kCompute); SetupColorAttachment(&p, 0); - SetupDepthAttachment(&p); + SetupDepthStencilAttachment(&p); Result r = p.AddShader(&c, kShaderTypeCompute); EXPECT_TRUE(r.IsSuccess()) << r.Error(); @@ -250,7 +250,7 @@ TEST_F(PipelineTest, ComputePipelineRequiresComputeShader) { TEST_F(PipelineTest, ComputePipelineWithoutShader) { Pipeline p(PipelineType::kCompute); SetupColorAttachment(&p, 0); - SetupDepthAttachment(&p); + SetupDepthStencilAttachment(&p); Result r = p.Validate(); EXPECT_FALSE(r.IsSuccess()) << r.Error(); @@ -343,7 +343,7 @@ TEST_F(PipelineTest, Clone) { p.SetFramebufferHeight(600); SetupColorAttachment(&p, 0); - SetupDepthAttachment(&p); + SetupDepthStencilAttachment(&p); Shader f(kShaderTypeFragment); p.AddShader(&f, kShaderTypeFragment); diff --git a/src/vkscript/parser.cc b/src/vkscript/parser.cc index 7a173d032..3434a305d 100644 --- a/src/vkscript/parser.cc +++ b/src/vkscript/parser.cc @@ -198,17 +198,17 @@ Result Parser::ProcessRequireBlock(const SectionParser::Section& section) { } auto* pipeline = script_->GetPipeline(kDefaultPipelineName); - if (pipeline->GetDepthBuffer().buffer != nullptr) + if (pipeline->GetDepthStencilBuffer().buffer != nullptr) return Result("Only one depthstencil command allowed"); auto fmt = MakeUnique(type.get()); // Generate and add a depth buffer - auto depth_buf = pipeline->GenerateDefaultDepthAttachmentBuffer(); + auto depth_buf = pipeline->GenerateDefaultDepthStencilAttachmentBuffer(); depth_buf->SetFormat(fmt.get()); script_->RegisterFormat(std::move(fmt)); script_->RegisterType(std::move(type)); - Result r = pipeline->SetDepthBuffer(depth_buf.get()); + Result r = pipeline->SetDepthStencilBuffer(depth_buf.get()); if (!r.IsSuccess()) return r; diff --git a/src/vulkan/device.cc b/src/vulkan/device.cc index 74fade950..edbc69e89 100644 --- a/src/vulkan/device.cc +++ b/src/vulkan/device.cc @@ -565,7 +565,7 @@ bool Device::IsFormatSupportedByPhysicalDevice(const Format& format, flag = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT; is_buffer_type_image = true; break; - case BufferType::kDepth: + case BufferType::kDepthStencil: flag = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT; is_buffer_type_image = true; break; diff --git a/src/vulkan/engine_vulkan.cc b/src/vulkan/engine_vulkan.cc index d4a402802..8db66813a 100644 --- a/src/vulkan/engine_vulkan.cc +++ b/src/vulkan/engine_vulkan.cc @@ -158,13 +158,12 @@ Result EngineVulkan::CreatePipeline(amber::Pipeline* pipeline) { return Result("Vulkan color attachment format is not supported"); } - Format* depth_fmt = nullptr; - if (pipeline->GetDepthBuffer().buffer) { - const auto& depth_info = pipeline->GetDepthBuffer(); + if (pipeline->GetDepthStencilBuffer().buffer) { + const auto& depth_stencil_info = pipeline->GetDepthStencilBuffer(); - depth_fmt = depth_info.buffer->GetFormat(); - if (!device_->IsFormatSupportedByPhysicalDevice(*depth_fmt, - depth_info.type)) { + auto fmt = depth_stencil_info.buffer->GetFormat(); + if (!device_->IsFormatSupportedByPhysicalDevice(*fmt, + depth_stencil_info.type)) { return Result("Vulkan depth attachment format is not supported"); } } @@ -184,8 +183,9 @@ Result EngineVulkan::CreatePipeline(amber::Pipeline* pipeline) { return r; } else { vk_pipeline = MakeUnique( - device_.get(), pipeline->GetColorAttachments(), depth_fmt, - engine_data.fence_timeout_ms, stage_create_info); + device_.get(), pipeline->GetColorAttachments(), + pipeline->GetDepthStencilBuffer(), engine_data.fence_timeout_ms, + stage_create_info); r = vk_pipeline->AsGraphics()->Initialize(pipeline->GetFramebufferWidth(), pipeline->GetFramebufferHeight(), diff --git a/src/vulkan/frame_buffer.cc b/src/vulkan/frame_buffer.cc index d042bd4b8..1b0ed2965 100644 --- a/src/vulkan/frame_buffer.cc +++ b/src/vulkan/frame_buffer.cc @@ -29,10 +29,12 @@ namespace vulkan { FrameBuffer::FrameBuffer( Device* device, const std::vector& color_attachments, + amber::Pipeline::BufferInfo depth_stencil_attachment, uint32_t width, uint32_t height) : device_(device), color_attachments_(color_attachments), + depth_stencil_attachment_(depth_stencil_attachment), width_(width), height_(height) {} @@ -43,8 +45,7 @@ FrameBuffer::~FrameBuffer() { } } -Result FrameBuffer::Initialize(VkRenderPass render_pass, - const Format* depth_format) { +Result FrameBuffer::Initialize(VkRenderPass render_pass) { std::vector attachments; if (!color_attachments_.empty()) { @@ -77,22 +78,23 @@ Result FrameBuffer::Initialize(VkRenderPass render_pass, } } - if (depth_format && depth_format->IsFormatKnown()) { - depth_image_ = MakeUnique( - device_, *depth_format, - static_cast(depth_format->HasStencilComponent() - ? VK_IMAGE_ASPECT_DEPTH_BIT | - VK_IMAGE_ASPECT_STENCIL_BIT - : VK_IMAGE_ASPECT_DEPTH_BIT), + if (depth_stencil_attachment_.buffer && + depth_stencil_attachment_.buffer->GetFormat()->IsFormatKnown()) { + depth_stencil_image_ = MakeUnique( + device_, *depth_stencil_attachment_.buffer->GetFormat(), + static_cast( + depth_stencil_attachment_.buffer->GetFormat()->HasStencilComponent() + ? VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT + : VK_IMAGE_ASPECT_DEPTH_BIT), VK_IMAGE_TYPE_2D, width_, height_, depth_, 1u, 0u, 1u); - Result r = depth_image_->Initialize( + Result r = depth_stencil_image_->Initialize( VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); if (!r.IsSuccess()) return r; - attachments.push_back(depth_image_->GetVkImageView()); + attachments.push_back(depth_stencil_image_->GetVkImageView()); } VkFramebufferCreateInfo frame_buffer_info = VkFramebufferCreateInfo(); @@ -121,8 +123,8 @@ void FrameBuffer::ChangeFrameLayout(CommandBuffer* command, for (auto& img : color_images_) img->ImageBarrier(command, color_layout, color_stage); - if (depth_image_) - depth_image_->ImageBarrier(command, depth_layout, depth_stage); + if (depth_stencil_image_) + depth_stencil_image_->ImageBarrier(command, depth_layout, depth_stage); } void FrameBuffer::ChangeFrameToDrawLayout(CommandBuffer* command) { @@ -153,9 +155,12 @@ void FrameBuffer::ChangeFrameToWriteLayout(CommandBuffer* command) { VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT); } -void FrameBuffer::TransferColorImagesToHost(CommandBuffer* command) { +void FrameBuffer::TransferImagesToHost(CommandBuffer* command) { for (auto& img : color_images_) img->CopyToHost(command); + + if (depth_stencil_image_) + depth_stencil_image_->CopyToHost(command); } void FrameBuffer::CopyImagesToBuffers() { @@ -167,11 +172,21 @@ void FrameBuffer::CopyImagesToBuffers() { std::memcpy(values->data(), img->HostAccessibleMemoryPtr(), info->buffer->GetSizeInBytes()); } + + if (depth_stencil_image_) { + auto* values = depth_stencil_attachment_.buffer->ValuePtr(); + values->resize(depth_stencil_attachment_.buffer->GetSizeInBytes()); + std::memcpy(values->data(), depth_stencil_image_->HostAccessibleMemoryPtr(), + depth_stencil_attachment_.buffer->GetSizeInBytes()); + } } -void FrameBuffer::TransferColorImagesToDevice(CommandBuffer* command) { +void FrameBuffer::TransferImagesToDevice(CommandBuffer* command) { for (auto& img : color_images_) img->CopyToDevice(command); + + if (depth_stencil_image_) + depth_stencil_image_->CopyToDevice(command); } void FrameBuffer::CopyBuffersToImages() { @@ -186,6 +201,16 @@ void FrameBuffer::CopyBuffersToImages() { std::memcpy(img->HostAccessibleMemoryPtr(), values->data(), info->buffer->GetSizeInBytes()); } + + if (depth_stencil_image_) { + auto* values = depth_stencil_attachment_.buffer->ValuePtr(); + // Nothing to do if our local buffer is empty + if (!values->empty()) { + std::memcpy(depth_stencil_image_->HostAccessibleMemoryPtr(), + values->data(), + depth_stencil_attachment_.buffer->GetSizeInBytes()); + } + } } } // namespace vulkan diff --git a/src/vulkan/frame_buffer.h b/src/vulkan/frame_buffer.h index 202726b1c..064b6d389 100644 --- a/src/vulkan/frame_buffer.h +++ b/src/vulkan/frame_buffer.h @@ -33,11 +33,12 @@ class FrameBuffer { FrameBuffer( Device* device, const std::vector& color_attachments, + amber::Pipeline::BufferInfo depth_stencil_attachment, uint32_t width, uint32_t height); ~FrameBuffer(); - Result Initialize(VkRenderPass render_pass, const Format* depth_format); + Result Initialize(VkRenderPass render_pass); void ChangeFrameToDrawLayout(CommandBuffer* command); void ChangeFrameToProbeLayout(CommandBuffer* command); @@ -51,8 +52,8 @@ class FrameBuffer { // Only record the command for copying the image that backs this // framebuffer to the host accessible buffer. The actual submission // of the command must be done later. - void TransferColorImagesToHost(CommandBuffer* command); - void TransferColorImagesToDevice(CommandBuffer* command); + void TransferImagesToHost(CommandBuffer* command); + void TransferImagesToDevice(CommandBuffer* command); void CopyImagesToBuffers(); void CopyBuffersToImages(); @@ -69,9 +70,10 @@ class FrameBuffer { Device* device_ = nullptr; std::vector color_attachments_; + amber::Pipeline::BufferInfo depth_stencil_attachment_; VkFramebuffer frame_ = VK_NULL_HANDLE; std::vector> color_images_; - std::unique_ptr depth_image_; + std::unique_ptr depth_stencil_image_; uint32_t width_ = 0; uint32_t height_ = 0; uint32_t depth_ = 1; diff --git a/src/vulkan/graphics_pipeline.cc b/src/vulkan/graphics_pipeline.cc index a63819a34..6c7245bc0 100644 --- a/src/vulkan/graphics_pipeline.cc +++ b/src/vulkan/graphics_pipeline.cc @@ -381,14 +381,14 @@ class RenderPassGuard { GraphicsPipeline::GraphicsPipeline( Device* device, const std::vector& color_buffers, - Format* depth_stencil_format, + amber::Pipeline::BufferInfo depth_stencil_buffer, uint32_t fence_timeout_ms, const std::vector& shader_stage_info) : Pipeline(PipelineType::kGraphics, device, fence_timeout_ms, shader_stage_info), - depth_stencil_format_(depth_stencil_format) { + depth_stencil_buffer_(depth_stencil_buffer) { for (const auto& info : color_buffers) color_buffers_.push_back(&info); } @@ -426,10 +426,11 @@ Result GraphicsPipeline::CreateRenderPass() { subpass_desc.colorAttachmentCount = static_cast(color_refer.size()); subpass_desc.pColorAttachments = color_refer.data(); - if (depth_stencil_format_ && depth_stencil_format_->IsFormatKnown()) { + if (depth_stencil_buffer_.buffer && + depth_stencil_buffer_.buffer->GetFormat()->IsFormatKnown()) { attachment_desc.push_back(kDefaultAttachmentDesc); attachment_desc.back().format = - device_->GetVkFormat(*depth_stencil_format_); + device_->GetVkFormat(*depth_stencil_buffer_.buffer->GetFormat()); attachment_desc.back().initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; attachment_desc.back().finalLayout = @@ -650,7 +651,8 @@ Result GraphicsPipeline::CreateVkGraphicsPipeline( } VkPipelineDepthStencilStateCreateInfo depthstencil_info; - if (depth_stencil_format_ && depth_stencil_format_->IsFormatKnown()) { + if (depth_stencil_buffer_.buffer && + depth_stencil_buffer_.buffer->GetFormat()->IsFormatKnown()) { depthstencil_info = GetVkPipelineDepthStencilInfo(pipeline_data); pipeline_info.pDepthStencilState = &depthstencil_info; } @@ -694,8 +696,9 @@ Result GraphicsPipeline::Initialize(uint32_t width, if (!r.IsSuccess()) return r; - frame_ = MakeUnique(device_, color_buffers_, width, height); - r = frame_->Initialize(render_pass_, depth_stencil_format_); + frame_ = MakeUnique(device_, color_buffers_, + depth_stencil_buffer_, width, height); + r = frame_->Initialize(render_pass_); if (!r.IsSuccess()) return r; @@ -741,7 +744,8 @@ Result GraphicsPipeline::SetClearColor(float r, float g, float b, float a) { } Result GraphicsPipeline::SetClearStencil(uint32_t stencil) { - if (!depth_stencil_format_ || !depth_stencil_format_->IsFormatKnown()) { + if (!depth_stencil_buffer_.buffer || + !depth_stencil_buffer_.buffer->GetFormat()->IsFormatKnown()) { return Result( "Vulkan::ClearStencilCommand No DepthStencil Buffer for FrameBuffer " "Exists"); @@ -752,7 +756,8 @@ Result GraphicsPipeline::SetClearStencil(uint32_t stencil) { } Result GraphicsPipeline::SetClearDepth(float depth) { - if (!depth_stencil_format_ || !depth_stencil_format_->IsFormatKnown()) { + if (!depth_stencil_buffer_.buffer || + !depth_stencil_buffer_.buffer->GetFormat()->IsFormatKnown()) { return Result( "Vulkan::ClearStencilCommand No DepthStencil Buffer for FrameBuffer " "Exists"); @@ -767,32 +772,13 @@ Result GraphicsPipeline::Clear() { colour_clear.color = { {clear_color_r_, clear_color_g_, clear_color_b_, clear_color_a_}}; - Result r = ClearBuffer(colour_clear, VK_IMAGE_ASPECT_COLOR_BIT); - if (!r.IsSuccess()) - return r; - - if (!depth_stencil_format_ || !depth_stencil_format_->IsFormatKnown()) - return {}; - - VkClearValue depth_clear; - depth_clear.depthStencil = {clear_depth_, clear_stencil_}; - - return ClearBuffer( - depth_clear, - depth_stencil_format_ && depth_stencil_format_->HasStencilComponent() - ? VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT - : VK_IMAGE_ASPECT_DEPTH_BIT); -} - -Result GraphicsPipeline::ClearBuffer(const VkClearValue& clear_value, - VkImageAspectFlags aspect) { CommandBufferGuard cmd_buf_guard(GetCommandBuffer()); if (!cmd_buf_guard.IsRecording()) return cmd_buf_guard.GetResult(); frame_->ChangeFrameToWriteLayout(GetCommandBuffer()); frame_->CopyBuffersToImages(); - frame_->TransferColorImagesToDevice(GetCommandBuffer()); + frame_->TransferImagesToDevice(GetCommandBuffer()); { RenderPassGuard render_pass_guard(this); @@ -800,9 +786,27 @@ Result GraphicsPipeline::ClearBuffer(const VkClearValue& clear_value, std::vector clears; for (size_t i = 0; i < color_buffers_.size(); ++i) { VkClearAttachment clear_attachment = VkClearAttachment(); - clear_attachment.aspectMask = aspect; + clear_attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; clear_attachment.colorAttachment = static_cast(i); - clear_attachment.clearValue = clear_value; + clear_attachment.clearValue = colour_clear; + + clears.push_back(clear_attachment); + } + + if (depth_stencil_buffer_.buffer && + depth_stencil_buffer_.buffer->GetFormat()->IsFormatKnown()) { + VkClearValue depth_stencil_clear; + depth_stencil_clear.depthStencil = {clear_depth_, clear_stencil_}; + + VkImageAspectFlags aspect = VK_IMAGE_ASPECT_DEPTH_BIT; + if (depth_stencil_buffer_.buffer->GetFormat()->HasStencilComponent()) + aspect |= VK_IMAGE_ASPECT_STENCIL_BIT; + + VkClearAttachment clear_attachment = VkClearAttachment(); + clear_attachment.aspectMask = aspect; + clear_attachment.colorAttachment = + static_cast(color_buffers_.size()); + clear_attachment.clearValue = depth_stencil_clear; clears.push_back(clear_attachment); } @@ -817,7 +821,7 @@ Result GraphicsPipeline::ClearBuffer(const VkClearValue& clear_value, clears.data(), 1, &clear_rect); } - frame_->TransferColorImagesToHost(command_.get()); + frame_->TransferImagesToHost(command_.get()); Result r = cmd_buf_guard.Submit(GetFenceTimeout()); if (!r.IsSuccess()) @@ -861,7 +865,7 @@ Result GraphicsPipeline::Draw(const DrawArraysCommand* command, frame_->ChangeFrameToWriteLayout(GetCommandBuffer()); frame_->CopyBuffersToImages(); - frame_->TransferColorImagesToDevice(GetCommandBuffer()); + frame_->TransferImagesToDevice(GetCommandBuffer()); { RenderPassGuard render_pass_guard(this); @@ -909,7 +913,7 @@ Result GraphicsPipeline::Draw(const DrawArraysCommand* command, } } - frame_->TransferColorImagesToHost(command_.get()); + frame_->TransferImagesToHost(command_.get()); r = cmd_buf_guard.Submit(GetFenceTimeout()); if (!r.IsSuccess()) diff --git a/src/vulkan/graphics_pipeline.h b/src/vulkan/graphics_pipeline.h index e08bdc377..7076231d3 100644 --- a/src/vulkan/graphics_pipeline.h +++ b/src/vulkan/graphics_pipeline.h @@ -42,7 +42,7 @@ class GraphicsPipeline : public Pipeline { GraphicsPipeline( Device* device, const std::vector& color_buffers, - Format* depth_stencil_format, + amber::Pipeline::BufferInfo depth_stencil_buffer, uint32_t fence_timeout_ms, const std::vector&); ~GraphicsPipeline() override; @@ -52,8 +52,6 @@ class GraphicsPipeline : public Pipeline { Result SetIndexBuffer(Buffer* buffer); Result Clear(); - Result ClearBuffer(const VkClearValue& clear_value, - VkImageAspectFlags aspect); Result SetClearColor(float r, float g, float b, float a); Result SetClearStencil(uint32_t stencil); @@ -90,7 +88,7 @@ class GraphicsPipeline : public Pipeline { // color buffers are owned by the amber::Pipeline. std::vector color_buffers_; - Format* depth_stencil_format_; + amber::Pipeline::BufferInfo depth_stencil_buffer_; std::unique_ptr index_buffer_; uint32_t frame_width_ = 0; diff --git a/src/vulkan/image_descriptor.cc b/src/vulkan/image_descriptor.cc index ee52787a6..bcb744d52 100644 --- a/src/vulkan/image_descriptor.cc +++ b/src/vulkan/image_descriptor.cc @@ -70,11 +70,22 @@ Result ImageDescriptor::CreateResourceIfNeeded() { break; } + Format* fmt = amber_buffer->GetFormat(); + VkImageAspectFlags aspect = 0; + if (fmt->HasDepthComponent() && fmt->HasStencilComponent()) { + aspect = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + } else if (fmt->HasDepthComponent()) { + aspect = VK_IMAGE_ASPECT_DEPTH_BIT; + } else if (fmt->HasStencilComponent()) { + aspect = VK_IMAGE_ASPECT_DEPTH_BIT; + } else { + aspect = VK_IMAGE_ASPECT_COLOR_BIT; + } + transfer_image_ = MakeUnique( - device_, *amber_buffer->GetFormat(), VK_IMAGE_ASPECT_COLOR_BIT, - image_type, amber_buffer->GetWidth(), amber_buffer->GetHeight(), - amber_buffer->GetDepth(), amber_buffer->GetMipLevels(), base_mip_level_, - VK_REMAINING_MIP_LEVELS); + device_, *fmt, aspect, image_type, amber_buffer->GetWidth(), + amber_buffer->GetHeight(), amber_buffer->GetDepth(), + amber_buffer->GetMipLevels(), base_mip_level_, VK_REMAINING_MIP_LEVELS); VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; diff --git a/src/vulkan/transfer_image.cc b/src/vulkan/transfer_image.cc index c7d0058b5..59328cd7f 100644 --- a/src/vulkan/transfer_image.cc +++ b/src/vulkan/transfer_image.cc @@ -109,7 +109,15 @@ Result TransferImage::Initialize(VkImageUsageFlags usage) { if (!r.IsSuccess()) return r; - r = CreateVkImageView(); + if (aspect_ & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT) && + usage != VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + // Combined depth/stencil image used as a descriptor. Only one aspect can be + // used for the image view. + r = CreateVkImageView(VK_IMAGE_ASPECT_DEPTH_BIT); + } else { + r = CreateVkImageView(aspect_); + } + if (!r.IsSuccess()) return r; @@ -153,7 +161,7 @@ VkImageViewType TransferImage::GetImageViewType() const { return VK_IMAGE_VIEW_TYPE_2D; } -Result TransferImage::CreateVkImageView() { +Result TransferImage::CreateVkImageView(VkImageAspectFlags aspect) { VkImageViewCreateInfo image_view_info = VkImageViewCreateInfo(); image_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; image_view_info.image = image_; @@ -166,7 +174,7 @@ Result TransferImage::CreateVkImageView() { VK_COMPONENT_SWIZZLE_A, }; image_view_info.subresourceRange = { - aspect_, /* aspectMask */ + aspect, /* aspectMask */ base_mip_level_, /* baseMipLevel */ used_mip_levels_, /* levelCount */ 0, /* baseArrayLayer */ @@ -182,15 +190,23 @@ Result TransferImage::CreateVkImageView() { return {}; } -VkBufferImageCopy TransferImage::CreateBufferImageCopy(uint32_t mip_level) { +VkBufferImageCopy TransferImage::CreateBufferImageCopy( + VkImageAspectFlags aspect, + uint32_t mip_level) { VkBufferImageCopy copy_region = VkBufferImageCopy(); - copy_region.bufferOffset = 0; + if (aspect == VK_IMAGE_ASPECT_STENCIL_BIT) { + // Store stencil data at the end of the buffer after depth data. + copy_region.bufferOffset = + GetSizeInBytes() - image_info_.extent.width * image_info_.extent.height; + } else { + copy_region.bufferOffset = 0; + } // Row length of 0 results in tight packing of rows, so the row stride // is the number of texels times the texel stride. copy_region.bufferRowLength = 0; copy_region.bufferImageHeight = 0; copy_region.imageSubresource = { - aspect_, /* aspectMask */ + aspect, /* aspectMask */ mip_level, /* mipLevel */ 0, /* baseArrayLayer */ 1, /* layerCount */ @@ -203,12 +219,17 @@ VkBufferImageCopy TransferImage::CreateBufferImageCopy(uint32_t mip_level) { } void TransferImage::CopyToHost(CommandBuffer* command_buffer) { + const VkImageAspectFlagBits aspects[] = {VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_ASPECT_DEPTH_BIT, + VK_IMAGE_ASPECT_STENCIL_BIT}; std::vector copy_regions; uint32_t last_mip_level = used_mip_levels_ == VK_REMAINING_MIP_LEVELS ? mip_levels_ : base_mip_level_ + used_mip_levels_; for (uint32_t i = base_mip_level_; i < last_mip_level; i++) - copy_regions.push_back(CreateBufferImageCopy(i)); + for (auto aspect : aspects) + if (aspect_ & aspect) + copy_regions.push_back(CreateBufferImageCopy(aspect, i)); device_->GetPtrs()->vkCmdCopyImageToBuffer( command_buffer->GetVkCommandBuffer(), image_, @@ -219,12 +240,17 @@ void TransferImage::CopyToHost(CommandBuffer* command_buffer) { } void TransferImage::CopyToDevice(CommandBuffer* command_buffer) { + const VkImageAspectFlagBits aspects[] = {VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_ASPECT_DEPTH_BIT, + VK_IMAGE_ASPECT_STENCIL_BIT}; std::vector copy_regions; uint32_t last_mip_level = used_mip_levels_ == VK_REMAINING_MIP_LEVELS ? mip_levels_ : base_mip_level_ + used_mip_levels_; for (uint32_t i = base_mip_level_; i < last_mip_level; i++) - copy_regions.push_back(CreateBufferImageCopy(i)); + for (auto aspect : aspects) + if (aspect_ & aspect) + copy_regions.push_back(CreateBufferImageCopy(aspect, i)); device_->GetPtrs()->vkCmdCopyBufferToImage( command_buffer->GetVkCommandBuffer(), host_accessible_buffer_, image_, diff --git a/src/vulkan/transfer_image.h b/src/vulkan/transfer_image.h index e68b88e04..fbdfa2346 100644 --- a/src/vulkan/transfer_image.h +++ b/src/vulkan/transfer_image.h @@ -56,13 +56,14 @@ class TransferImage : public Resource { void CopyToHost(CommandBuffer* command_buffer) override; private: - Result CreateVkImageView(); + Result CreateVkImageView(VkImageAspectFlags aspect); Result AllocateAndBindMemoryToVkImage(VkImage image, VkDeviceMemory* memory, VkMemoryPropertyFlags flags, bool force_flags, uint32_t* memory_type_index); - VkBufferImageCopy CreateBufferImageCopy(uint32_t mip_level); + VkBufferImageCopy CreateBufferImageCopy(VkImageAspectFlags aspect, + uint32_t mip_level); VkImageViewType GetImageViewType() const; diff --git a/tests/cases/draw_rectangles_depth_test.amber b/tests/cases/draw_rectangles_depth_test.amber new file mode 100644 index 000000000..62c15a8d6 --- /dev/null +++ b/tests/cases/draw_rectangles_depth_test.amber @@ -0,0 +1,136 @@ +#!amber +# +# Copyright 2020 The Amber 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 +# +# https://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. + +SHADER vertex vert_shader GLSL +#version 430 + +layout(location = 0) in vec4 position; +layout(location = 0) out vec4 frag_color; + +layout(set = 0, binding = 0) readonly buffer block1 { + vec4 in_color; + float depth; +}; + +void main() { + gl_Position = vec4(position.xy, depth, 1.0); + frag_color = in_color; +} +END + +SHADER fragment frag_shader GLSL +#version 430 + +layout(location = 0) in vec4 frag_color; +layout(location = 0) out vec4 final_color; + +void main() { + final_color = frag_color; +} +END + +SHADER vertex vert_shader_tex GLSL +#version 430 +layout(location = 0) in vec4 position; +layout(location = 1) in vec2 texcoords_in; +layout(location = 0) out vec2 texcoords_out; +void main() { + gl_Position = position; + texcoords_out = texcoords_in; +} +END + +SHADER fragment frag_shader_tex GLSL +#version 430 +layout(location = 0) in vec2 texcoords_in; +layout(location = 0) out vec4 color_out; +uniform layout(set=0, binding=0) sampler2D tex_sampler; +void main() { + float f = texture(tex_sampler, texcoords_in).r; + color_out = vec4(f, f, f, 1); +} +END + +BUFFER data_buf1 DATA_TYPE float DATA 1.0 0.0 0.0 1.0 0.3 END +BUFFER data_buf2 DATA_TYPE float DATA 0.0 1.0 0.0 1.0 0.5 END + +BUFFER position DATA_TYPE vec2 DATA +-1.0 -1.0 + 1.0 -1.0 + 1.0 1.0 +-1.0 1.0 +END +BUFFER texcoords DATA_TYPE vec2 DATA +0.0 0.0 +1.0 0.0 +1.0 1.0 +0.0 1.0 +END + +BUFFER framebuffer FORMAT B8G8R8A8_UNORM +BUFFER ddump FORMAT B8G8R8A8_UNORM +BUFFER depthstencil FORMAT D32_SFLOAT_S8_UINT + +SAMPLER sampler + +PIPELINE graphics pipeline1 + ATTACH vert_shader + ATTACH frag_shader + + FRAMEBUFFER_SIZE 256 256 + BIND BUFFER framebuffer AS color LOCATION 0 + BIND BUFFER depthstencil AS depth_stencil + BIND BUFFER data_buf1 AS storage DESCRIPTOR_SET 0 BINDING 0 + + DEPTH + TEST on + WRITE on + COMPARE less + CLAMP off + BOUNDS min 0.0 max 1.0 + BIAS constant 0.0 clamp 0.0 slope 0.0 + END +END + +DERIVE_PIPELINE pipeline2 FROM pipeline1 + BIND BUFFER data_buf2 AS storage DESCRIPTOR_SET 0 BINDING 0 +END + +PIPELINE graphics depthdump + ATTACH vert_shader_tex + ATTACH frag_shader_tex + BIND BUFFER depthstencil AS combined_image_sampler SAMPLER sampler DESCRIPTOR_SET 0 BINDING 0 + VERTEX_DATA position LOCATION 0 + VERTEX_DATA texcoords LOCATION 1 + FRAMEBUFFER_SIZE 256 256 + BIND BUFFER ddump AS color LOCATION 0 +END + +CLEAR_DEPTH pipeline1 1.0 +CLEAR_COLOR pipeline1 255 255 255 255 +CLEAR pipeline1 +RUN pipeline1 DRAW_RECT POS 0 0 SIZE 200 200 +RUN pipeline2 DRAW_RECT POS 56 56 SIZE 200 200 +RUN depthdump DRAW_ARRAY AS TRIANGLE_FAN START_IDX 0 COUNT 4 + +EXPECT framebuffer IDX 0 0 SIZE 1 1 EQ_RGBA 255 0 0 255 +EXPECT framebuffer IDX 128 128 SIZE 1 1 EQ_RGBA 255 0 0 255 +EXPECT framebuffer IDX 255 255 SIZE 1 1 EQ_RGBA 0 255 0 255 +EXPECT depthstencil IDX 0 EQ 0.3 +EXPECT ddump IDX 0 0 SIZE 1 1 EQ_RGBA 76 76 76 255 TOLERANCE 5% 5% 5% 0 +EXPECT ddump IDX 255 0 SIZE 1 1 EQ_RGBA 255 255 255 255 TOLERANCE 5% 5% 5% 0 +EXPECT ddump IDX 0 255 SIZE 1 1 EQ_RGBA 255 255 255 255 TOLERANCE 5% 5% 5% 0 +EXPECT ddump IDX 255 255 SIZE 1 1 EQ_RGBA 128 128 128 255 TOLERANCE 5% 5% 5% 0 diff --git a/tests/cases/draw_rectangles_stencil_test.amber b/tests/cases/draw_rectangles_stencil_test.amber new file mode 100644 index 000000000..b9c3dd687 --- /dev/null +++ b/tests/cases/draw_rectangles_stencil_test.amber @@ -0,0 +1,149 @@ +#!amber +# +# Copyright 2020 The Amber 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 +# +# https://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. + +SHADER vertex vert_shader GLSL +#version 430 + +layout(location = 0) in vec4 position; +layout(location = 0) out vec4 frag_color; + +layout(set = 0, binding = 0) readonly buffer block1 { + vec4 in_color; +}; + +void main() { + gl_Position = position; + frag_color = in_color; +} +END + +SHADER fragment frag_shader GLSL +#version 430 + +layout(location = 0) in vec4 frag_color; +layout(location = 0) out vec4 final_color; + +void main() { + final_color = frag_color; +} +END + +BUFFER data_buf1 DATA_TYPE float DATA 1.0 0.0 0.0 1.0 END +BUFFER data_buf2 DATA_TYPE float DATA 0.0 1.0 0.0 1.0 END +BUFFER data_buf3 DATA_TYPE float DATA 0.0 0.0 1.0 1.0 END +BUFFER data_buf4 DATA_TYPE float DATA 1.0 0.0 1.0 1.0 END +BUFFER data_buf5 DATA_TYPE float DATA 1.0 1.0 0.0 1.0 END + +BUFFER framebuffer FORMAT B8G8R8A8_UNORM +BUFFER depthstencil FORMAT D32_SFLOAT_S8_UINT + +SAMPLER sampler + +PIPELINE graphics pipeline1 + ATTACH vert_shader + ATTACH frag_shader + + FRAMEBUFFER_SIZE 256 256 + BIND BUFFER framebuffer AS color LOCATION 0 + BIND BUFFER depthstencil AS depth_stencil + BIND BUFFER data_buf1 AS storage DESCRIPTOR_SET 0 BINDING 0 + + STENCIL front_and_back + TEST on + FAIL replace + PASS replace + DEPTH_FAIL keep + COMPARE always + COMPARE_MASK 255 + WRITE_MASK 255 + REFERENCE 32 + END +END + +DERIVE_PIPELINE pipeline2 FROM pipeline1 + BIND BUFFER data_buf2 AS storage DESCRIPTOR_SET 0 BINDING 0 + + STENCIL front_and_back + TEST on + FAIL increment_and_clamp + PASS invert + DEPTH_FAIL keep + COMPARE equal + COMPARE_MASK 255 + WRITE_MASK 255 + REFERENCE 32 + END +END + +DERIVE_PIPELINE pipeline3 FROM pipeline1 + BIND BUFFER data_buf3 AS storage DESCRIPTOR_SET 0 BINDING 0 + + STENCIL front_and_back + TEST on + FAIL keep + PASS keep + DEPTH_FAIL keep + COMPARE equal + COMPARE_MASK 255 + WRITE_MASK 255 + REFERENCE 32 + END +END + +DERIVE_PIPELINE pipeline4 FROM pipeline1 + BIND BUFFER data_buf4 AS storage DESCRIPTOR_SET 0 BINDING 0 + + STENCIL front_and_back + TEST on + FAIL keep + PASS keep + DEPTH_FAIL keep + COMPARE equal + COMPARE_MASK 255 + WRITE_MASK 255 + REFERENCE 1 + END +END + +DERIVE_PIPELINE pipeline5 FROM pipeline1 + BIND BUFFER data_buf5 AS storage DESCRIPTOR_SET 0 BINDING 0 + + STENCIL front_and_back + TEST on + FAIL keep + PASS keep + DEPTH_FAIL keep + COMPARE equal + COMPARE_MASK 255 + WRITE_MASK 255 + REFERENCE 223 + END +END + +CLEAR_STENCIL pipeline1 0 +CLEAR_COLOR pipeline1 255 255 255 255 +CLEAR pipeline1 +RUN pipeline1 DRAW_RECT POS 0 0 SIZE 200 200 +RUN pipeline2 DRAW_RECT POS 56 56 SIZE 200 200 +RUN pipeline3 DRAW_RECT POS 0 0 SIZE 256 256 +RUN pipeline4 DRAW_RECT POS 0 0 SIZE 256 256 +RUN pipeline5 DRAW_RECT POS 0 0 SIZE 256 256 + +EXPECT framebuffer IDX 0 0 SIZE 1 1 EQ_RGBA 0 0 255 255 +EXPECT framebuffer IDX 128 128 SIZE 1 1 EQ_RGBA 255 255 0 255 +EXPECT framebuffer IDX 255 255 SIZE 1 1 EQ_RGBA 255 0 255 255 +EXPECT framebuffer IDX 255 0 SIZE 1 1 EQ_RGBA 255 255 255 255 +EXPECT framebuffer IDX 0 255 SIZE 1 1 EQ_RGBA 255 255 255 255 From 0f8e451a64be370d4328de91e079065156955d02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ari=20Suonp=C3=A4=C3=A4?= Date: Fri, 3 Apr 2020 14:44:00 +0300 Subject: [PATCH 2/7] Use .f for floats. --- src/amberscript/parser_depth_test.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/amberscript/parser_depth_test.cc b/src/amberscript/parser_depth_test.cc index 944fb8439..24f8d618e 100644 --- a/src/amberscript/parser_depth_test.cc +++ b/src/amberscript/parser_depth_test.cc @@ -59,12 +59,12 @@ END)"; ASSERT_TRUE(pipeline->GetPipelineData()->GetEnableDepthTest()); ASSERT_TRUE(pipeline->GetPipelineData()->GetEnableDepthWrite()); ASSERT_TRUE(pipeline->GetPipelineData()->GetEnableDepthClamp()); - ASSERT_FLOAT_EQ(1.5, pipeline->GetPipelineData()->GetMinDepthBounds()); - ASSERT_FLOAT_EQ(6.7, pipeline->GetPipelineData()->GetMaxDepthBounds()); - ASSERT_FLOAT_EQ(2.1, + ASSERT_FLOAT_EQ(1.5f, pipeline->GetPipelineData()->GetMinDepthBounds()); + ASSERT_FLOAT_EQ(6.7f, pipeline->GetPipelineData()->GetMaxDepthBounds()); + ASSERT_FLOAT_EQ(2.1f, pipeline->GetPipelineData()->GetDepthBiasConstantFactor()); - ASSERT_FLOAT_EQ(3.5, pipeline->GetPipelineData()->GetDepthBiasClamp()); - ASSERT_FLOAT_EQ(5.5, pipeline->GetPipelineData()->GetDepthBiasSlopeFactor()); + ASSERT_FLOAT_EQ(3.5f, pipeline->GetPipelineData()->GetDepthBiasClamp()); + ASSERT_FLOAT_EQ(5.5f, pipeline->GetPipelineData()->GetDepthBiasSlopeFactor()); } TEST_F(AmberScriptParserTest, DepthTestMissingValue) { From 4c8da408968b317ce687b7a5f8dde19428498464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ari=20Suonp=C3=A4=C3=A4?= Date: Fri, 3 Apr 2020 15:57:32 +0300 Subject: [PATCH 3/7] Image aspect bug fixes. --- src/vulkan/frame_buffer.cc | 13 ++++++++----- src/vulkan/transfer_image.cc | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/vulkan/frame_buffer.cc b/src/vulkan/frame_buffer.cc index 1b0ed2965..816b2a4e9 100644 --- a/src/vulkan/frame_buffer.cc +++ b/src/vulkan/frame_buffer.cc @@ -80,12 +80,15 @@ Result FrameBuffer::Initialize(VkRenderPass render_pass) { if (depth_stencil_attachment_.buffer && depth_stencil_attachment_.buffer->GetFormat()->IsFormatKnown()) { + VkImageAspectFlags aspect = 0; + if (depth_stencil_attachment_.buffer->GetFormat()->HasDepthComponent()) + aspect |= VK_IMAGE_ASPECT_DEPTH_BIT; + if (depth_stencil_attachment_.buffer->GetFormat()->HasStencilComponent()) + aspect |= VK_IMAGE_ASPECT_STENCIL_BIT; + assert(aspect != 0); + depth_stencil_image_ = MakeUnique( - device_, *depth_stencil_attachment_.buffer->GetFormat(), - static_cast( - depth_stencil_attachment_.buffer->GetFormat()->HasStencilComponent() - ? VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT - : VK_IMAGE_ASPECT_DEPTH_BIT), + device_, *depth_stencil_attachment_.buffer->GetFormat(), aspect, VK_IMAGE_TYPE_2D, width_, height_, depth_, 1u, 0u, 1u); Result r = depth_stencil_image_->Initialize( diff --git a/src/vulkan/transfer_image.cc b/src/vulkan/transfer_image.cc index 59328cd7f..4b3509b85 100644 --- a/src/vulkan/transfer_image.cc +++ b/src/vulkan/transfer_image.cc @@ -110,7 +110,7 @@ Result TransferImage::Initialize(VkImageUsageFlags usage) { return r; if (aspect_ & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT) && - usage != VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + !(usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { // Combined depth/stencil image used as a descriptor. Only one aspect can be // used for the image view. r = CreateVkImageView(VK_IMAGE_ASPECT_DEPTH_BIT); From c3d72e90661f9a4d223d9a18b3f0896520e7b753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ari=20Suonp=C3=A4=C3=A4?= Date: Sun, 5 Apr 2020 09:38:45 +0300 Subject: [PATCH 4/7] Fixed clang errors. --- src/amberscript/parser.cc | 98 ++++++++++++++++++++------------- src/command_data.h | 6 +- src/vulkan/graphics_pipeline.cc | 10 ++-- 3 files changed, 70 insertions(+), 44 deletions(-) diff --git a/src/amberscript/parser.cc b/src/amberscript/parser.cc index 23870a4ff..524279ab5 100644 --- a/src/amberscript/parser.cc +++ b/src/amberscript/parser.cc @@ -152,25 +152,47 @@ ImageDimension StrToImageDimension(const std::string& str) { return ImageDimension::kUnknown; } -std::map compare_ops = { - {"never", CompareOp::kNever}, - {"less", CompareOp::kLess}, - {"equal", CompareOp::kEqual}, - {"less_or_equal", CompareOp::kLessOrEqual}, - {"greater", CompareOp::kGreater}, - {"not_equal", CompareOp::kNotEqual}, - {"greater_or_equal", CompareOp::kGreaterOrEqual}, - {"always", CompareOp::kAlways}}; - -std::map stencil_ops = { - {"keep", StencilOp::kKeep}, - {"zero", StencilOp::kZero}, - {"replace", StencilOp::kReplace}, - {"increment_and_clamp", StencilOp::kIncrementAndClamp}, - {"decrement_and_clamp", StencilOp::kDecrementAndClamp}, - {"invert", StencilOp::kInvert}, - {"increment_and_wrap", StencilOp::kIncrementAndWrap}, - {"decrement_and_wrap", StencilOp::kDecrementAndWrap}}; +CompareOp StrToCompareOp(const std::string& str) { + if (str == "never") + return CompareOp::kNever; + if (str == "less") + return CompareOp::kLess; + if (str == "equal") + return CompareOp::kEqual; + if (str == "less_or_equal") + return CompareOp::kLessOrEqual; + if (str == "greater") + return CompareOp::kGreater; + if (str == "not_equal") + return CompareOp::kNotEqual; + if (str == "greater_or_equal") + return CompareOp::kGreaterOrEqual; + if (str == "always") + return CompareOp::kAlways; + + return CompareOp::kUnknown; +} + +StencilOp StrToStencilOp(const std::string& str) { + if (str == "keep") + return StencilOp::kKeep; + if (str == "zero") + return StencilOp::kZero; + if (str == "replace") + return StencilOp::kReplace; + if (str == "increment_and_clamp") + return StencilOp::kIncrementAndClamp; + if (str == "decrement_and_clamp") + return StencilOp::kDecrementAndClamp; + if (str == "invert") + return StencilOp::kInvert; + if (str == "increment_and_wrap") + return StencilOp::kIncrementAndWrap; + if (str == "decrement_and_wrap") + return StencilOp::kDecrementAndWrap; + + return StencilOp::kUnknown; +} } // namespace @@ -1177,9 +1199,9 @@ Result Parser::ParsePipelineDepth(Pipeline* pipeline) { if (!token->IsIdentifier()) return Result("invalid value for COMPARE"); - auto it = compare_ops.find(token->AsString()); - if (it != compare_ops.end()) { - pipeline->GetPipelineData()->SetDepthCompareOp(it->second); + CompareOp compare_op = StrToCompareOp(token->AsString()); + if (compare_op != CompareOp::kUnknown) { + pipeline->GetPipelineData()->SetDepthCompareOp(compare_op); } else { return Result("invalid value for COMPARE: " + token->AsString()); } @@ -1286,12 +1308,12 @@ Result Parser::ParsePipelineStencil(Pipeline* pipeline) { if (!token->IsIdentifier()) return Result("STENCIL invalid value for FAIL"); - auto it = stencil_ops.find(token->AsString()); - if (it != stencil_ops.end()) { + StencilOp stencil_op = StrToStencilOp(token->AsString()); + if (stencil_op != StencilOp::kUnknown) { if (setFront) - pipeline->GetPipelineData()->SetFrontFailOp(it->second); + pipeline->GetPipelineData()->SetFrontFailOp(stencil_op); if (setBack) - pipeline->GetPipelineData()->SetBackFailOp(it->second); + pipeline->GetPipelineData()->SetBackFailOp(stencil_op); } else { return Result("STENCIL invalid value for FAIL: " + token->AsString()); } @@ -1301,12 +1323,12 @@ Result Parser::ParsePipelineStencil(Pipeline* pipeline) { if (!token->IsIdentifier()) return Result("STENCIL invalid value for PASS"); - auto it = stencil_ops.find(token->AsString()); - if (it != stencil_ops.end()) { + StencilOp stencil_op = StrToStencilOp(token->AsString()); + if (stencil_op != StencilOp::kUnknown) { if (setFront) - pipeline->GetPipelineData()->SetFrontPassOp(it->second); + pipeline->GetPipelineData()->SetFrontPassOp(stencil_op); if (setBack) - pipeline->GetPipelineData()->SetBackPassOp(it->second); + pipeline->GetPipelineData()->SetBackPassOp(stencil_op); } else { return Result("STENCIL invalid value for PASS: " + token->AsString()); } @@ -1316,12 +1338,12 @@ Result Parser::ParsePipelineStencil(Pipeline* pipeline) { if (!token->IsIdentifier()) return Result("STENCIL invalid value for DEPTH_FAIL"); - auto it = stencil_ops.find(token->AsString()); - if (it != stencil_ops.end()) { + StencilOp stencil_op = StrToStencilOp(token->AsString()); + if (stencil_op != StencilOp::kUnknown) { if (setFront) - pipeline->GetPipelineData()->SetFrontDepthFailOp(it->second); + pipeline->GetPipelineData()->SetFrontDepthFailOp(stencil_op); if (setBack) - pipeline->GetPipelineData()->SetBackDepthFailOp(it->second); + pipeline->GetPipelineData()->SetBackDepthFailOp(stencil_op); } else { return Result("STENCIL invalid value for DEPTH_FAIL: " + token->AsString()); @@ -1332,12 +1354,12 @@ Result Parser::ParsePipelineStencil(Pipeline* pipeline) { if (!token->IsIdentifier()) return Result("STENCIL invalid value for COMPARE"); - auto it = compare_ops.find(token->AsString()); - if (it != compare_ops.end()) { + CompareOp compare_op = StrToCompareOp(token->AsString()); + if (compare_op != CompareOp::kUnknown) { if (setFront) - pipeline->GetPipelineData()->SetFrontCompareOp(it->second); + pipeline->GetPipelineData()->SetFrontCompareOp(compare_op); if (setBack) - pipeline->GetPipelineData()->SetBackCompareOp(it->second); + pipeline->GetPipelineData()->SetBackCompareOp(compare_op); } else { return Result("STENCIL invalid value for COMPARE: " + token->AsString()); diff --git a/src/command_data.h b/src/command_data.h index 430533cd1..98ec4053d 100644 --- a/src/command_data.h +++ b/src/command_data.h @@ -61,7 +61,8 @@ enum ColorMask { }; enum class CompareOp : uint8_t { - kNever = 0, + kUnknown = 0, + kNever, kLess, kEqual, kLessOrEqual, @@ -72,7 +73,8 @@ enum class CompareOp : uint8_t { }; enum class StencilOp : uint8_t { - kKeep = 0, + kUnknown = 0, + kKeep, kZero, kReplace, kIncrementAndClamp, diff --git a/src/vulkan/graphics_pipeline.cc b/src/vulkan/graphics_pipeline.cc index 6c7245bc0..63b226f4e 100644 --- a/src/vulkan/graphics_pipeline.cc +++ b/src/vulkan/graphics_pipeline.cc @@ -90,9 +90,10 @@ VkStencilOp ToVkStencilOp(StencilOp op) { return VK_STENCIL_OP_INCREMENT_AND_WRAP; case StencilOp::kDecrementAndWrap: return VK_STENCIL_OP_DECREMENT_AND_WRAP; + default: + assert(false && "Vulkan::Unknown StencilOp"); + return VK_STENCIL_OP_KEEP; } - assert(false && "Vulkan::Unknown StencilOp"); - return VK_STENCIL_OP_KEEP; } VkCompareOp ToVkCompareOp(CompareOp op) { @@ -113,9 +114,10 @@ VkCompareOp ToVkCompareOp(CompareOp op) { return VK_COMPARE_OP_GREATER_OR_EQUAL; case CompareOp::kAlways: return VK_COMPARE_OP_ALWAYS; + default: + assert(false && "Vulkan::Unknown CompareOp"); + return VK_COMPARE_OP_NEVER; } - assert(false && "Vulkan::Unknown CompareOp"); - return VK_COMPARE_OP_NEVER; } VkPolygonMode ToVkPolygonMode(PolygonMode mode) { From cf9f046eeb91b5190c236af1c535f99e58868010 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ari=20Suonp=C3=A4=C3=A4?= Date: Mon, 6 Apr 2020 08:02:36 +0300 Subject: [PATCH 5/7] Define copy constructor for PipelineData. --- src/pipeline_data.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pipeline_data.h b/src/pipeline_data.h index e44dd4ec9..dc67c03e1 100644 --- a/src/pipeline_data.h +++ b/src/pipeline_data.h @@ -28,6 +28,8 @@ class PipelineData { ~PipelineData(); PipelineData(const PipelineData&); + PipelineData& operator=(const PipelineData&) = default; + void SetTopology(Topology topo) { topology_ = topo; } Topology GetTopology() const { return topology_; } From 615333fb97593cb38385fbe0d83e4c076b12be81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ari=20Suonp=C3=A4=C3=A4?= Date: Tue, 7 Apr 2020 09:41:17 +0300 Subject: [PATCH 6/7] Renamed some of the depth and stencil parameters. --- src/amberscript/parser.cc | 32 +++++++------ src/amberscript/parser_depth_test.cc | 10 ++-- src/amberscript/parser_stencil_test.cc | 48 +++++++++---------- tests/cases/draw_rectangles_depth_test.amber | 2 +- .../cases/draw_rectangles_stencil_test.amber | 40 ++++++++-------- 5 files changed, 67 insertions(+), 65 deletions(-) diff --git a/src/amberscript/parser.cc b/src/amberscript/parser.cc index 524279ab5..9d31c5d57 100644 --- a/src/amberscript/parser.cc +++ b/src/amberscript/parser.cc @@ -1193,17 +1193,17 @@ Result Parser::ParsePipelineDepth(Pipeline* pipeline) { pipeline->GetPipelineData()->SetEnableDepthWrite(false); else return Result("invalid value for WRITE: " + token->AsString()); - } else if (token->AsString() == "COMPARE") { + } else if (token->AsString() == "COMPARE_OP") { token = tokenizer_->NextToken(); if (!token->IsIdentifier()) - return Result("invalid value for COMPARE"); + return Result("invalid value for COMPARE_OP"); CompareOp compare_op = StrToCompareOp(token->AsString()); if (compare_op != CompareOp::kUnknown) { pipeline->GetPipelineData()->SetDepthCompareOp(compare_op); } else { - return Result("invalid value for COMPARE: " + token->AsString()); + return Result("invalid value for COMPARE_OP: " + token->AsString()); } } else if (token->AsString() == "BOUNDS") { token = tokenizer_->NextToken(); @@ -1302,11 +1302,11 @@ Result Parser::ParsePipelineStencil(Pipeline* pipeline) { pipeline->GetPipelineData()->SetEnableStencilTest(false); else return Result("STENCIL invalid value for TEST: " + token->AsString()); - } else if (token->AsString() == "FAIL") { + } else if (token->AsString() == "FAIL_OP") { token = tokenizer_->NextToken(); if (!token->IsIdentifier()) - return Result("STENCIL invalid value for FAIL"); + return Result("STENCIL invalid value for FAIL_OP"); StencilOp stencil_op = StrToStencilOp(token->AsString()); if (stencil_op != StencilOp::kUnknown) { @@ -1315,13 +1315,14 @@ Result Parser::ParsePipelineStencil(Pipeline* pipeline) { if (setBack) pipeline->GetPipelineData()->SetBackFailOp(stencil_op); } else { - return Result("STENCIL invalid value for FAIL: " + token->AsString()); + return Result("STENCIL invalid value for FAIL_OP: " + + token->AsString()); } - } else if (token->AsString() == "PASS") { + } else if (token->AsString() == "PASS_OP") { token = tokenizer_->NextToken(); if (!token->IsIdentifier()) - return Result("STENCIL invalid value for PASS"); + return Result("STENCIL invalid value for PASS_OP"); StencilOp stencil_op = StrToStencilOp(token->AsString()); if (stencil_op != StencilOp::kUnknown) { @@ -1330,13 +1331,14 @@ Result Parser::ParsePipelineStencil(Pipeline* pipeline) { if (setBack) pipeline->GetPipelineData()->SetBackPassOp(stencil_op); } else { - return Result("STENCIL invalid value for PASS: " + token->AsString()); + return Result("STENCIL invalid value for PASS_OP: " + + token->AsString()); } - } else if (token->AsString() == "DEPTH_FAIL") { + } else if (token->AsString() == "DEPTH_FAIL_OP") { token = tokenizer_->NextToken(); if (!token->IsIdentifier()) - return Result("STENCIL invalid value for DEPTH_FAIL"); + return Result("STENCIL invalid value for DEPTH_FAIL_OP"); StencilOp stencil_op = StrToStencilOp(token->AsString()); if (stencil_op != StencilOp::kUnknown) { @@ -1345,14 +1347,14 @@ Result Parser::ParsePipelineStencil(Pipeline* pipeline) { if (setBack) pipeline->GetPipelineData()->SetBackDepthFailOp(stencil_op); } else { - return Result("STENCIL invalid value for DEPTH_FAIL: " + + return Result("STENCIL invalid value for DEPTH_FAIL_OP: " + token->AsString()); } - } else if (token->AsString() == "COMPARE") { + } else if (token->AsString() == "COMPARE_OP") { token = tokenizer_->NextToken(); if (!token->IsIdentifier()) - return Result("STENCIL invalid value for COMPARE"); + return Result("STENCIL invalid value for COMPARE_OP"); CompareOp compare_op = StrToCompareOp(token->AsString()); if (compare_op != CompareOp::kUnknown) { @@ -1361,7 +1363,7 @@ Result Parser::ParsePipelineStencil(Pipeline* pipeline) { if (setBack) pipeline->GetPipelineData()->SetBackCompareOp(compare_op); } else { - return Result("STENCIL invalid value for COMPARE: " + + return Result("STENCIL invalid value for COMPARE_OP: " + token->AsString()); } } else if (token->AsString() == "COMPARE_MASK") { diff --git a/src/amberscript/parser_depth_test.cc b/src/amberscript/parser_depth_test.cc index 24f8d618e..68ddf4b44 100644 --- a/src/amberscript/parser_depth_test.cc +++ b/src/amberscript/parser_depth_test.cc @@ -38,7 +38,7 @@ PIPELINE graphics my_pipeline DEPTH TEST on WRITE on - COMPARE less_or_equal + COMPARE_OP less_or_equal CLAMP on BOUNDS min 1.5 max 6.7 BIAS constant 2.1 clamp 3.5 slope 5.5 @@ -246,14 +246,14 @@ PIPELINE graphics my_pipeline DEPTH TEST on - COMPARE + COMPARE_OP END END)"; Parser parser; Result r = parser.Parse(in); ASSERT_FALSE(r.IsSuccess()) << r.Error(); - EXPECT_EQ("18: invalid value for COMPARE", r.Error()); + EXPECT_EQ("18: invalid value for COMPARE_OP", r.Error()); } TEST_F(AmberScriptParserTest, DepthCompareInvalidValue) { @@ -273,14 +273,14 @@ PIPELINE graphics my_pipeline DEPTH TEST on - COMPARE foo + COMPARE_OP foo END END)"; Parser parser; Result r = parser.Parse(in); ASSERT_FALSE(r.IsSuccess()) << r.Error(); - EXPECT_EQ("17: invalid value for COMPARE: foo", r.Error()); + EXPECT_EQ("17: invalid value for COMPARE_OP: foo", r.Error()); } TEST_F(AmberScriptParserTest, DepthBoundsExpectingMin) { diff --git a/src/amberscript/parser_stencil_test.cc b/src/amberscript/parser_stencil_test.cc index d8cc89582..f4492da8f 100644 --- a/src/amberscript/parser_stencil_test.cc +++ b/src/amberscript/parser_stencil_test.cc @@ -37,20 +37,20 @@ PIPELINE graphics my_pipeline STENCIL front TEST on - FAIL increment_and_clamp - PASS invert - DEPTH_FAIL keep - COMPARE equal + FAIL_OP increment_and_clamp + PASS_OP invert + DEPTH_FAIL_OP keep + COMPARE_OP equal COMPARE_MASK 1 WRITE_MASK 2 REFERENCE 3 END STENCIL back TEST on - FAIL zero - PASS increment_and_wrap - DEPTH_FAIL replace - COMPARE greater + FAIL_OP zero + PASS_OP increment_and_wrap + DEPTH_FAIL_OP replace + COMPARE_OP greater COMPARE_MASK 4 WRITE_MASK 5 REFERENCE 6 @@ -213,14 +213,14 @@ PIPELINE graphics my_pipeline STENCIL front TEST on - FAIL + FAIL_OP END END)"; Parser parser; Result r = parser.Parse(in); ASSERT_FALSE(r.IsSuccess()) << r.Error(); - EXPECT_EQ("18: STENCIL invalid value for FAIL", r.Error()); + EXPECT_EQ("18: STENCIL invalid value for FAIL_OP", r.Error()); } TEST_F(AmberScriptParserTest, StencilFailInvalidValue) { @@ -240,14 +240,14 @@ PIPELINE graphics my_pipeline STENCIL front TEST on - FAIL foo + FAIL_OP foo END END)"; Parser parser; Result r = parser.Parse(in); ASSERT_FALSE(r.IsSuccess()) << r.Error(); - EXPECT_EQ("17: STENCIL invalid value for FAIL: foo", r.Error()); + EXPECT_EQ("17: STENCIL invalid value for FAIL_OP: foo", r.Error()); } TEST_F(AmberScriptParserTest, StencilPassMissingValue) { @@ -267,14 +267,14 @@ PIPELINE graphics my_pipeline STENCIL front TEST on - PASS + PASS_OP END END)"; Parser parser; Result r = parser.Parse(in); ASSERT_FALSE(r.IsSuccess()) << r.Error(); - EXPECT_EQ("18: STENCIL invalid value for PASS", r.Error()); + EXPECT_EQ("18: STENCIL invalid value for PASS_OP", r.Error()); } TEST_F(AmberScriptParserTest, StencilPassInvalidValue) { @@ -294,14 +294,14 @@ PIPELINE graphics my_pipeline STENCIL front TEST on - PASS foo + PASS_OP foo END END)"; Parser parser; Result r = parser.Parse(in); ASSERT_FALSE(r.IsSuccess()) << r.Error(); - EXPECT_EQ("17: STENCIL invalid value for PASS: foo", r.Error()); + EXPECT_EQ("17: STENCIL invalid value for PASS_OP: foo", r.Error()); } TEST_F(AmberScriptParserTest, StencilDepthFailMissingValue) { @@ -321,14 +321,14 @@ PIPELINE graphics my_pipeline STENCIL front TEST on - DEPTH_FAIL + DEPTH_FAIL_OP END END)"; Parser parser; Result r = parser.Parse(in); ASSERT_FALSE(r.IsSuccess()) << r.Error(); - EXPECT_EQ("18: STENCIL invalid value for DEPTH_FAIL", r.Error()); + EXPECT_EQ("18: STENCIL invalid value for DEPTH_FAIL_OP", r.Error()); } TEST_F(AmberScriptParserTest, StencilDepthFailInvalidValue) { @@ -348,14 +348,14 @@ PIPELINE graphics my_pipeline STENCIL front TEST on - DEPTH_FAIL foo + DEPTH_FAIL_OP foo END END)"; Parser parser; Result r = parser.Parse(in); ASSERT_FALSE(r.IsSuccess()) << r.Error(); - EXPECT_EQ("17: STENCIL invalid value for DEPTH_FAIL: foo", r.Error()); + EXPECT_EQ("17: STENCIL invalid value for DEPTH_FAIL_OP: foo", r.Error()); } TEST_F(AmberScriptParserTest, StencilCompareMissingValue) { @@ -375,14 +375,14 @@ PIPELINE graphics my_pipeline STENCIL front TEST on - COMPARE + COMPARE_OP END END)"; Parser parser; Result r = parser.Parse(in); ASSERT_FALSE(r.IsSuccess()) << r.Error(); - EXPECT_EQ("18: STENCIL invalid value for COMPARE", r.Error()); + EXPECT_EQ("18: STENCIL invalid value for COMPARE_OP", r.Error()); } TEST_F(AmberScriptParserTest, StencilCompareInvalidValue) { @@ -402,14 +402,14 @@ PIPELINE graphics my_pipeline STENCIL front TEST on - COMPARE foo + COMPARE_OP foo END END)"; Parser parser; Result r = parser.Parse(in); ASSERT_FALSE(r.IsSuccess()) << r.Error(); - EXPECT_EQ("17: STENCIL invalid value for COMPARE: foo", r.Error()); + EXPECT_EQ("17: STENCIL invalid value for COMPARE_OP: foo", r.Error()); } TEST_F(AmberScriptParserTest, StencilCompareMaskMissingValue) { diff --git a/tests/cases/draw_rectangles_depth_test.amber b/tests/cases/draw_rectangles_depth_test.amber index 62c15a8d6..797e99b3f 100644 --- a/tests/cases/draw_rectangles_depth_test.amber +++ b/tests/cases/draw_rectangles_depth_test.amber @@ -98,7 +98,7 @@ PIPELINE graphics pipeline1 DEPTH TEST on WRITE on - COMPARE less + COMPARE_OP less CLAMP off BOUNDS min 0.0 max 1.0 BIAS constant 0.0 clamp 0.0 slope 0.0 diff --git a/tests/cases/draw_rectangles_stencil_test.amber b/tests/cases/draw_rectangles_stencil_test.amber index b9c3dd687..d9790bf26 100644 --- a/tests/cases/draw_rectangles_stencil_test.amber +++ b/tests/cases/draw_rectangles_stencil_test.amber @@ -63,10 +63,10 @@ PIPELINE graphics pipeline1 STENCIL front_and_back TEST on - FAIL replace - PASS replace - DEPTH_FAIL keep - COMPARE always + FAIL_OP replace + PASS_OP replace + DEPTH_FAIL_OP keep + COMPARE_OP always COMPARE_MASK 255 WRITE_MASK 255 REFERENCE 32 @@ -78,10 +78,10 @@ DERIVE_PIPELINE pipeline2 FROM pipeline1 STENCIL front_and_back TEST on - FAIL increment_and_clamp - PASS invert - DEPTH_FAIL keep - COMPARE equal + FAIL_OP increment_and_clamp + PASS_OP invert + DEPTH_FAIL_OP keep + COMPARE_OP equal COMPARE_MASK 255 WRITE_MASK 255 REFERENCE 32 @@ -93,10 +93,10 @@ DERIVE_PIPELINE pipeline3 FROM pipeline1 STENCIL front_and_back TEST on - FAIL keep - PASS keep - DEPTH_FAIL keep - COMPARE equal + FAIL_OP keep + PASS_OP keep + DEPTH_FAIL_OP keep + COMPARE_OP equal COMPARE_MASK 255 WRITE_MASK 255 REFERENCE 32 @@ -108,10 +108,10 @@ DERIVE_PIPELINE pipeline4 FROM pipeline1 STENCIL front_and_back TEST on - FAIL keep - PASS keep - DEPTH_FAIL keep - COMPARE equal + FAIL_OP keep + PASS_OP keep + DEPTH_FAIL_OP keep + COMPARE_OP equal COMPARE_MASK 255 WRITE_MASK 255 REFERENCE 1 @@ -123,10 +123,10 @@ DERIVE_PIPELINE pipeline5 FROM pipeline1 STENCIL front_and_back TEST on - FAIL keep - PASS keep - DEPTH_FAIL keep - COMPARE equal + FAIL_OP keep + PASS_OP keep + DEPTH_FAIL_OP keep + COMPARE_OP equal COMPARE_MASK 255 WRITE_MASK 255 REFERENCE 223 From f5aecabd9e4766516c21793c43553f19ee32b498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ari=20Suonp=C3=A4=C3=A4?= Date: Wed, 8 Apr 2020 08:26:38 +0300 Subject: [PATCH 7/7] Updated documentation. --- docs/amber_script.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/amber_script.md b/docs/amber_script.md index 953861ee8..3a8afa723 100644 --- a/docs/amber_script.md +++ b/docs/amber_script.md @@ -385,7 +385,7 @@ The following commands are all specified within the `PIPELINE` command. DEPTH TEST {test_enable} WRITE {write_enable} - COMPARE {compare_op} + COMPARE_OP {compare_op} CLAMP {clamp_enable} BOUNDS min {bound_min} max {bounds_max} BIAS constant {bias_constant} clamp {bias_clamp} slope {bias_slope} @@ -409,10 +409,10 @@ The following commands are all specified within the `PIPELINE` command. # and |reference| are 8bit unsigned integer values (range 0..255). STENCIL {face} TEST {test_enable} - FAIL {fail_op} - PASS {pass_op} - DEPTH_FAIL {depth_fail_op} - COMPARE {compare_op} + FAIL_OP {fail_op} + PASS_OP {pass_op} + DEPTH_FAIL_OP {depth_fail_op} + COMPARE_OP {compare_op} COMPARE_MASK {compare_mask} WRITE_MASK {write_mask} REFERENCE {reference}