aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgnl21 <gnl021@gmail.com>2021-03-16 14:14:57 +0000
committerGitHub <noreply@github.com>2021-03-16 14:14:57 +0000
commitdd917bb97dd1a2957ca3e5d2d75f463e5ac91caa (patch)
treeb4c39043f47908ee868a4590252459b86bf2f4e2
parentdabae26164714abf951c6815a2b4513260f7c6a4 (diff)
downloadamber-dd917bb97dd1a2957ca3e5d2d75f463e5ac91caa.tar.gz
Add VIEWPORT to AmberScript (#944)
This allows setting the viewport for graphics pipelines.
-rw-r--r--docs/amber_script.md6
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/amberscript/parser.cc71
-rw-r--r--src/amberscript/parser.h1
-rw-r--r--src/amberscript/parser_viewport_test.cc388
-rw-r--r--src/pipeline_data.h20
-rw-r--r--src/vulkan/graphics_pipeline.cc10
-rw-r--r--tests/cases/viewport.amber59
-rw-r--r--tests/cases/viewport_depth.amber61
9 files changed, 617 insertions, 0 deletions
diff --git a/docs/amber_script.md b/docs/amber_script.md
index 57e0632..3d88b5a 100644
--- a/docs/amber_script.md
+++ b/docs/amber_script.md
@@ -485,6 +485,12 @@ The following commands are all specified within the `PIPELINE` command.
```
```groovy
+ # Set the viewport size. If no viewport is provided then it defaults to the
+ # whole framebuffer size. Depth range defaults to 0 to 1.
+ VIEWPORT {x} {y} SIZE {width} {height} [MIN_DEPTH {mind}] [MAX_DEPTH {maxd}]
+```
+
+```groovy
# Set subgroup size control setting. Require that subgroups must be launched
# with all invocations active for given shader. Allow SubgroupSize to vary
# for given shader. Require a specific SubgroupSize the for given shader.
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 00e3e54..901681f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -159,6 +159,7 @@ if (${AMBER_ENABLE_TESTS})
amberscript/parser_struct_test.cc
amberscript/parser_subgroup_size_control_test.cc
amberscript/parser_test.cc
+ amberscript/parser_viewport_test.cc
buffer_test.cc
command_data_test.cc
descriptor_set_and_binding_parser_test.cc
diff --git a/src/amberscript/parser.cc b/src/amberscript/parser.cc
index 50760f0..3b40d00 100644
--- a/src/amberscript/parser.cc
+++ b/src/amberscript/parser.cc
@@ -602,6 +602,8 @@ Result Parser::ParsePipelineBody(const std::string& cmd_name,
r = ParsePipelineShaderOptimizations(pipeline.get());
} else if (tok == "FRAMEBUFFER_SIZE") {
r = ParsePipelineFramebufferSize(pipeline.get());
+ } else if (tok == "VIEWPORT") {
+ r = ParsePipelineViewport(pipeline.get());
} else if (tok == "BIND") {
r = ParsePipelineBind(pipeline.get());
} else if (tok == "VERTEX_DATA") {
@@ -949,6 +951,75 @@ Result Parser::ParsePipelineFramebufferSize(Pipeline* pipeline) {
return ValidateEndOfStatement("FRAMEBUFFER_SIZE command");
}
+Result Parser::ParsePipelineViewport(Pipeline* pipeline) {
+ Viewport vp;
+ vp.mind = 0.0f;
+ vp.maxd = 1.0f;
+
+ float val[2];
+ for (int i = 0; i < 2; i++) {
+ auto token = tokenizer_->NextToken();
+ if (token->IsEOL() || token->IsEOS())
+ return Result("missing offset for VIEWPORT command");
+ Result r = token->ConvertToDouble();
+ if (!r.IsSuccess())
+ return Result("invalid offset for VIEWPORT command");
+
+ val[i] = token->AsFloat();
+ }
+ vp.x = val[0];
+ vp.y = val[1];
+
+ auto token = tokenizer_->NextToken();
+ if (!token->IsIdentifier() || token->AsString() != "SIZE")
+ return Result("missing SIZE for VIEWPORT command");
+
+ for (int i = 0; i < 2; i++) {
+ token = tokenizer_->NextToken();
+ if (token->IsEOL() || token->IsEOS())
+ return Result("missing size for VIEWPORT command");
+ Result r = token->ConvertToDouble();
+ if (!r.IsSuccess())
+ return Result("invalid size for VIEWPORT command");
+
+ val[i] = token->AsFloat();
+ }
+ vp.w = val[0];
+ vp.h = val[1];
+
+ token = tokenizer_->PeekNextToken();
+ while (token->IsIdentifier()) {
+ if (token->AsString() == "MIN_DEPTH") {
+ tokenizer_->NextToken();
+ token = tokenizer_->NextToken();
+ if (token->IsEOL() || token->IsEOS())
+ return Result("missing min_depth for VIEWPORT command");
+ Result r = token->ConvertToDouble();
+ if (!r.IsSuccess())
+ return Result("invalid min_depth for VIEWPORT command");
+
+ vp.mind = token->AsFloat();
+ }
+ if (token->AsString() == "MAX_DEPTH") {
+ tokenizer_->NextToken();
+ token = tokenizer_->NextToken();
+ if (token->IsEOL() || token->IsEOS())
+ return Result("missing max_depth for VIEWPORT command");
+ Result r = token->ConvertToDouble();
+ if (!r.IsSuccess())
+ return Result("invalid max_depth for VIEWPORT command");
+
+ vp.maxd = token->AsFloat();
+ }
+
+ token = tokenizer_->PeekNextToken();
+ }
+
+ pipeline->GetPipelineData()->SetViewport(vp);
+
+ return ValidateEndOfStatement("VIEWPORT command");
+}
+
Result Parser::ToBufferType(const std::string& name, BufferType* type) {
assert(type);
if (name == "color")
diff --git a/src/amberscript/parser.h b/src/amberscript/parser.h
index e8cb835..6fb25ce 100644
--- a/src/amberscript/parser.h
+++ b/src/amberscript/parser.h
@@ -65,6 +65,7 @@ class Parser : public amber::Parser {
Result ParsePipelineShaderCompileOptions(Pipeline*);
Result ParsePipelineSubgroup(Pipeline* pipeline);
Result ParsePipelineFramebufferSize(Pipeline*);
+ Result ParsePipelineViewport(Pipeline*);
Result ParsePipelineBind(Pipeline*);
Result ParsePipelineVertexData(Pipeline*);
Result ParsePipelineIndexData(Pipeline*);
diff --git a/src/amberscript/parser_viewport_test.cc b/src/amberscript/parser_viewport_test.cc
new file mode 100644
index 0000000..ec19fb2
--- /dev/null
+++ b/src/amberscript/parser_viewport_test.cc
@@ -0,0 +1,388 @@
+// Copyright 2021 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, NoViewport) {
+ 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
+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_FALSE(pipeline->GetPipelineData()->HasViewportData());
+}
+
+TEST_F(AmberScriptParserTest, ViewportNoDepth) {
+ 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
+
+ VIEWPORT 5.0 7.0 SIZE 10.0 12.0
+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_TRUE(pipeline->GetPipelineData()->HasViewportData());
+ ASSERT_FLOAT_EQ(5.0f, pipeline->GetPipelineData()->GetViewport().x);
+ ASSERT_FLOAT_EQ(7.0f, pipeline->GetPipelineData()->GetViewport().y);
+ ASSERT_FLOAT_EQ(10.0f, pipeline->GetPipelineData()->GetViewport().w);
+ ASSERT_FLOAT_EQ(12.0f, pipeline->GetPipelineData()->GetViewport().h);
+ ASSERT_FLOAT_EQ(0.0f, pipeline->GetPipelineData()->GetViewport().mind);
+ ASSERT_FLOAT_EQ(1.0f, pipeline->GetPipelineData()->GetViewport().maxd);
+}
+
+TEST_F(AmberScriptParserTest, ViewportMinDepth) {
+ 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
+
+ VIEWPORT 12.2 9.7 SIZE 0.5 106.1 MIN_DEPTH 0.3
+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_TRUE(pipeline->GetPipelineData()->HasViewportData());
+ ASSERT_FLOAT_EQ(12.2f, pipeline->GetPipelineData()->GetViewport().x);
+ ASSERT_FLOAT_EQ(9.7f, pipeline->GetPipelineData()->GetViewport().y);
+ ASSERT_FLOAT_EQ(0.5f, pipeline->GetPipelineData()->GetViewport().w);
+ ASSERT_FLOAT_EQ(106.1f, pipeline->GetPipelineData()->GetViewport().h);
+ ASSERT_FLOAT_EQ(0.3f, pipeline->GetPipelineData()->GetViewport().mind);
+ ASSERT_FLOAT_EQ(1.0f, pipeline->GetPipelineData()->GetViewport().maxd);
+}
+
+TEST_F(AmberScriptParserTest, ViewportMaxDepth) {
+ 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
+
+ VIEWPORT 12.2 9.7 SIZE 0.5 106.1 MAX_DEPTH 0.456
+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_TRUE(pipeline->GetPipelineData()->HasViewportData());
+ ASSERT_FLOAT_EQ(12.2f, pipeline->GetPipelineData()->GetViewport().x);
+ ASSERT_FLOAT_EQ(9.7f, pipeline->GetPipelineData()->GetViewport().y);
+ ASSERT_FLOAT_EQ(0.5f, pipeline->GetPipelineData()->GetViewport().w);
+ ASSERT_FLOAT_EQ(106.1f, pipeline->GetPipelineData()->GetViewport().h);
+ ASSERT_FLOAT_EQ(0.0f, pipeline->GetPipelineData()->GetViewport().mind);
+ ASSERT_FLOAT_EQ(0.456f, pipeline->GetPipelineData()->GetViewport().maxd);
+}
+
+TEST_F(AmberScriptParserTest, ViewportAllValues) {
+ 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
+
+ VIEWPORT -0.6 5.2 SIZE 13.8 9.4 MIN_DEPTH 0.5 MAX_DEPTH 0.6
+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_TRUE(pipeline->GetPipelineData()->HasViewportData());
+ ASSERT_FLOAT_EQ(-0.6f, pipeline->GetPipelineData()->GetViewport().x);
+ ASSERT_FLOAT_EQ(5.2f, pipeline->GetPipelineData()->GetViewport().y);
+ ASSERT_FLOAT_EQ(13.8f, pipeline->GetPipelineData()->GetViewport().w);
+ ASSERT_FLOAT_EQ(9.4f, pipeline->GetPipelineData()->GetViewport().h);
+ ASSERT_FLOAT_EQ(0.5f, pipeline->GetPipelineData()->GetViewport().mind);
+ ASSERT_FLOAT_EQ(0.6f, pipeline->GetPipelineData()->GetViewport().maxd);
+}
+
+TEST_F(AmberScriptParserTest, ViewportIntegers) {
+ 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
+
+ VIEWPORT -2 7 SIZE 15 20 MIN_DEPTH 1 MAX_DEPTH 2
+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_TRUE(pipeline->GetPipelineData()->HasViewportData());
+ ASSERT_FLOAT_EQ(-2.0f, pipeline->GetPipelineData()->GetViewport().x);
+ ASSERT_FLOAT_EQ(7.0f, pipeline->GetPipelineData()->GetViewport().y);
+ ASSERT_FLOAT_EQ(15.0f, pipeline->GetPipelineData()->GetViewport().w);
+ ASSERT_FLOAT_EQ(20.0f, pipeline->GetPipelineData()->GetViewport().h);
+ ASSERT_FLOAT_EQ(1.0f, pipeline->GetPipelineData()->GetViewport().mind);
+ ASSERT_FLOAT_EQ(2.0f, pipeline->GetPipelineData()->GetViewport().maxd);
+}
+
+TEST_F(AmberScriptParserTest, ViewportMixedIntegers) {
+ 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
+
+ VIEWPORT -2 13.1 SIZE 15.9 20
+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_TRUE(pipeline->GetPipelineData()->HasViewportData());
+ ASSERT_FLOAT_EQ(-2.0f, pipeline->GetPipelineData()->GetViewport().x);
+ ASSERT_FLOAT_EQ(13.1f, pipeline->GetPipelineData()->GetViewport().y);
+ ASSERT_FLOAT_EQ(15.9f, pipeline->GetPipelineData()->GetViewport().w);
+ ASSERT_FLOAT_EQ(20.0f, pipeline->GetPipelineData()->GetViewport().h);
+ ASSERT_FLOAT_EQ(0.0f, pipeline->GetPipelineData()->GetViewport().mind);
+ ASSERT_FLOAT_EQ(1.0f, pipeline->GetPipelineData()->GetViewport().maxd);
+}
+
+TEST_F(AmberScriptParserTest, ViewportInvalidMissingSize) {
+ 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
+
+ VIEWPORT 0.0 2.0 12.0 24.0
+END)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess()) << r.Error();
+ EXPECT_EQ("15: missing SIZE for VIEWPORT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ViewportInvalidSizeNotOptional) {
+ 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
+
+ VIEWPORT 0.0 2.0
+END)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess()) << r.Error();
+ EXPECT_EQ("16: missing SIZE for VIEWPORT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ViewportInvalidMissingOffset) {
+ 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
+
+ VIEWPORT 0.0 SIZE 12.0 24.0
+END)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess()) << r.Error();
+ EXPECT_EQ("15: invalid offset for VIEWPORT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ViewportInvalidMissingSizeValue) {
+ 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
+
+ VIEWPORT 0.0 2.0 SIZE 12.0
+END)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess()) << r.Error();
+ EXPECT_EQ("16: missing size for VIEWPORT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ViewportInvalidMissingDepthValue) {
+ 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
+
+ VIEWPORT 0.0 2.0 SIZE 12.0 24.0 MIN_DEPTH MAX_DEPTH 1.0
+END)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess()) << r.Error();
+ EXPECT_EQ("15: invalid min_depth for VIEWPORT command", r.Error());
+}
+
+} // namespace amberscript
+} // namespace amber
diff --git a/src/pipeline_data.h b/src/pipeline_data.h
index dc67c03..9a3b4d1 100644
--- a/src/pipeline_data.h
+++ b/src/pipeline_data.h
@@ -21,6 +21,15 @@
namespace amber {
+struct Viewport {
+ float x;
+ float y;
+ float w;
+ float h;
+ float mind;
+ float maxd;
+};
+
/// Stores information used to configure a pipeline.
class PipelineData {
public:
@@ -161,6 +170,14 @@ class PipelineData {
void SetAlphaBlendOp(BlendOp op) { alpha_blend_op_ = op; }
BlendOp GetAlphaBlendOp() const { return alpha_blend_op_; }
+ void SetViewport(const Viewport& v) {
+ has_viewport_data = true;
+ vp = v;
+ }
+
+ bool HasViewportData() const { return has_viewport_data; }
+ const Viewport& GetViewport() const { return vp; }
+
private:
StencilOp front_fail_op_ = StencilOp::kKeep;
StencilOp front_pass_op_ = StencilOp::kKeep;
@@ -213,6 +230,9 @@ class PipelineData {
float depth_bias_slope_factor_ = 0.0f;
float min_depth_bounds_ = 0.0f;
float max_depth_bounds_ = 0.0f;
+
+ bool has_viewport_data = false;
+ Viewport vp;
};
} // namespace amber
diff --git a/src/vulkan/graphics_pipeline.cc b/src/vulkan/graphics_pipeline.cc
index b83bea1..5536440 100644
--- a/src/vulkan/graphics_pipeline.cc
+++ b/src/vulkan/graphics_pipeline.cc
@@ -579,6 +579,16 @@ Result GraphicsPipeline::CreateVkGraphicsPipeline(
0, 0, static_cast<float>(frame_width_), static_cast<float>(frame_height_),
0, 1};
+ if (pipeline_data->HasViewportData()) {
+ Viewport vp = pipeline_data->GetViewport();
+ viewport.x = vp.x;
+ viewport.y = vp.y;
+ viewport.width = vp.w;
+ viewport.height = vp.h;
+ viewport.minDepth = vp.mind;
+ viewport.maxDepth = vp.maxd;
+ }
+
VkRect2D scissor = {{0, 0}, {frame_width_, frame_height_}};
VkPipelineViewportStateCreateInfo viewport_info =
diff --git a/tests/cases/viewport.amber b/tests/cases/viewport.amber
new file mode 100644
index 0000000..ca9b0a5
--- /dev/null
+++ b/tests/cases/viewport.amber
@@ -0,0 +1,59 @@
+#!amber
+#
+# Copyright 2021 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;
+
+void main() {
+ gl_Position = vec4(position.xy, 0.5, 1.0);
+}
+END
+
+SHADER fragment frag_shader GLSL
+#version 430
+
+layout(location = 0) out vec4 final_color;
+
+void main() {
+ final_color = vec4(0, 1, 0, 1);
+}
+END
+
+BUFFER framebuffer FORMAT B8G8R8A8_UNORM
+
+PIPELINE graphics pipeline1
+ ATTACH vert_shader
+ ATTACH frag_shader
+
+ FRAMEBUFFER_SIZE 256 256
+ VIEWPORT 10.0 10.0 SIZE 100.0 100.0
+
+ BIND BUFFER framebuffer AS color LOCATION 0
+END
+
+CLEAR_COLOR pipeline1 255 255 255 255
+CLEAR pipeline1
+RUN pipeline1 DRAW_RECT POS 0 0 SIZE 256 256
+
+# Check within the viewport
+EXPECT framebuffer IDX 10 10 SIZE 100 100 EQ_RGBA 0 255 0 255
+# Check the borders were untouched
+EXPECT framebuffer IDX 0 0 SIZE 10 256 EQ_RGBA 255 255 255 255
+EXPECT framebuffer IDX 110 0 SIZE 146 256 EQ_RGBA 255 255 255 255
+EXPECT framebuffer IDX 10 0 SIZE 100 10 EQ_RGBA 255 255 255 255
+EXPECT framebuffer IDX 10 110 SIZE 100 146 EQ_RGBA 255 255 255 255
diff --git a/tests/cases/viewport_depth.amber b/tests/cases/viewport_depth.amber
new file mode 100644
index 0000000..2bf7a9e
--- /dev/null
+++ b/tests/cases/viewport_depth.amber
@@ -0,0 +1,61 @@
+#!amber
+#
+# Copyright 2021 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;
+
+void main() {
+ gl_Position = vec4(position.xy, 0.5, 1.0);
+}
+END
+
+SHADER fragment frag_shader GLSL
+#version 430
+
+layout(location = 0) out vec4 final_color;
+
+void main() {
+ final_color = vec4(0, 1, 0, 1);
+}
+END
+
+BUFFER framebuffer FORMAT B8G8R8A8_UNORM
+BUFFER depth FORMAT D32_SFLOAT
+
+PIPELINE graphics pipeline1
+ ATTACH vert_shader
+ ATTACH frag_shader
+
+ DEPTH
+ TEST on
+ WRITE on
+ END
+
+ FRAMEBUFFER_SIZE 256 256
+ VIEWPORT 0.0 0.0 SIZE 256.0 256.0 MIN_DEPTH 0.3 MAX_DEPTH 0.9
+
+ BIND BUFFER framebuffer AS color LOCATION 0
+ BIND BUFFER depth AS depth_stencil
+END
+
+CLEAR_DEPTH pipeline1 1.0
+CLEAR_COLOR pipeline1 255 255 255 255
+CLEAR pipeline1
+RUN pipeline1 DRAW_RECT POS 0 0 SIZE 256 256
+
+EXPECT depth IDX 0 TOLERANCE 1.0e-6 EQ 0.6