diff options
author | asuonpaa <34128694+asuonpaa@users.noreply.github.com> | 2021-11-12 12:25:00 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-12 10:25:00 +0000 |
commit | 5bd7d35a38e410892fb73c7a54fd2a20534480cd (patch) | |
tree | 6922c41a2aa5ad8d37c70818ae887f1567f0e299 | |
parent | 02dc821ced6d786af712fcacd13462210bb34009 (diff) | |
download | amber-5bd7d35a38e410892fb73c7a54fd2a20534480cd.tar.gz |
Add support for multisample resolve (#970)
Multisample images were already supported, but graphics pipelines were
not able to resolve these into single sample images.
-rw-r--r-- | docs/amber_script.md | 5 | ||||
-rw-r--r-- | src/amberscript/parser.cc | 4 | ||||
-rw-r--r-- | src/amberscript/parser_bind_test.cc | 127 | ||||
-rw-r--r-- | src/buffer.h | 4 | ||||
-rw-r--r-- | src/pipeline.cc | 12 | ||||
-rw-r--r-- | src/pipeline.h | 9 | ||||
-rw-r--r-- | src/vulkan/device.cc | 1 | ||||
-rw-r--r-- | src/vulkan/engine_vulkan.cc | 4 | ||||
-rw-r--r-- | src/vulkan/frame_buffer.cc | 47 | ||||
-rw-r--r-- | src/vulkan/frame_buffer.h | 3 | ||||
-rw-r--r-- | src/vulkan/graphics_pipeline.cc | 38 | ||||
-rw-r--r-- | src/vulkan/graphics_pipeline.h | 4 | ||||
-rw-r--r-- | tests/cases/multisample_resolve.amber | 50 |
13 files changed, 301 insertions, 7 deletions
diff --git a/docs/amber_script.md b/docs/amber_script.md index 4161101..a0e4e54 100644 --- a/docs/amber_script.md +++ b/docs/amber_script.md @@ -555,6 +555,11 @@ contain image attachment content, depth/stencil content, uniform buffers, etc. # pipelines. BIND BUFFER {buffer_name} AS depth_stencil + # Attach |buffer_name| as a multisample resolve target. The order of resolve + # target images match with the order of color attachments that have more than + # one sample. + BIND BUFFER {buffer_name} AS resolve + # Attach |buffer_name| as the push_constant buffer. There can be only one # push constant buffer attached to a pipeline. BIND BUFFER {buffer_name} AS push_constant diff --git a/src/amberscript/parser.cc b/src/amberscript/parser.cc index dfc2cfb..c0f9475 100644 --- a/src/amberscript/parser.cc +++ b/src/amberscript/parser.cc @@ -1062,6 +1062,8 @@ Result Parser::ToBufferType(const std::string& name, BufferType* type) { *type = BufferType::kUniformTexelBuffer; else if (name == "storage_texel_buffer") *type = BufferType::kStorageTexelBuffer; + else if (name == "resolve") + *type = BufferType::kResolve; else return Result("unknown buffer_type: " + name); @@ -1176,6 +1178,8 @@ Result Parser::ParsePipelineBind(Pipeline* pipeline) { for (auto& buf : buffers) buf->SetSampler(sampler); + } else if (buffer_type == BufferType::kResolve) { + r = pipeline->AddResolveTarget(buffer); } } diff --git a/src/amberscript/parser_bind_test.cc b/src/amberscript/parser_bind_test.cc index a39b69e..8aac5e5 100644 --- a/src/amberscript/parser_bind_test.cc +++ b/src/amberscript/parser_bind_test.cc @@ -3508,5 +3508,132 @@ END r.Error()); } +TEST_F(AmberScriptParserTest, BindResolveTarget) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +IMAGE my_fb_ms DIM_2D WIDTH 64 HEIGHT 64 FORMAT R32G32B32A32_SFLOAT SAMPLES 4 +IMAGE my_fb DIM_2D WIDTH 64 HEIGHT 64 FORMAT R32G32B32A32_SFLOAT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + + FRAMEBUFFER_SIZE 64 64 + BIND BUFFER my_fb_ms AS color LOCATION 0 + BIND BUFFER my_fb AS resolve +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()); + + const auto* pipeline = pipelines[0].get(); + const auto& resolve_targets = pipeline->GetResolveTargets(); + ASSERT_EQ(1U, resolve_targets.size()); + + const auto& buf_info = resolve_targets[0]; + ASSERT_TRUE(buf_info.buffer != nullptr); + EXPECT_EQ(64u * 64u, buf_info.buffer->ElementCount()); + EXPECT_EQ(64u * 64u * 4u, buf_info.buffer->ValueCount()); + EXPECT_EQ(64u * 64u * 4u * sizeof(float), buf_info.buffer->GetSizeInBytes()); +} + +TEST_F(AmberScriptParserTest, BindResolveTargetMissingBuffer) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +BUFFER my_fb FORMAT R32G32B32A32_SFLOAT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + + BIND BUFFER AS resolve +END)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("12: unknown buffer: AS", r.Error()); +} + +TEST_F(AmberScriptParserTest, BindResolveTargetNonDeclaredBuffer) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +IMAGE my_fb_ms DIM_2D WIDTH 64 HEIGHT 64 FORMAT R32G32B32A32_SFLOAT SAMPLES 4 + +PIPELINE graphics my_pipeline +ATTACH my_shader +ATTACH my_fragment + +FRAMEBUFFER_SIZE 64 64 +BIND BUFFER my_fb_ms AS color LOCATION 0 +BIND BUFFER my_fb AS resolve +END)"; + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("14: unknown buffer: my_fb", r.Error()); +} + +TEST_F(AmberScriptParserTest, BindMultipleResolveTargets) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END +IMAGE my_fb_ms0 DIM_2D WIDTH 64 HEIGHT 64 FORMAT R32G32B32A32_SFLOAT SAMPLES 4 +IMAGE my_fb_ms1 DIM_2D WIDTH 64 HEIGHT 64 FORMAT R32G32B32A32_SFLOAT SAMPLES 4 +IMAGE my_fb_ms2 DIM_2D WIDTH 64 HEIGHT 64 FORMAT R32G32B32A32_SFLOAT SAMPLES 4 +IMAGE my_fb0 DIM_2D WIDTH 64 HEIGHT 64 FORMAT R32G32B32A32_SFLOAT +IMAGE my_fb1 DIM_2D WIDTH 64 HEIGHT 64 FORMAT R32G32B32A32_SFLOAT +IMAGE my_fb2 DIM_2D WIDTH 64 HEIGHT 64 FORMAT R32G32B32A32_SFLOAT + +PIPELINE graphics my_pipeline + ATTACH my_shader + ATTACH my_fragment + + FRAMEBUFFER_SIZE 64 64 + BIND BUFFER my_fb_ms0 AS color LOCATION 0 + BIND BUFFER my_fb_ms1 AS color LOCATION 1 + BIND BUFFER my_fb_ms2 AS color LOCATION 2 + BIND BUFFER my_fb0 AS resolve + BIND BUFFER my_fb1 AS resolve + BIND BUFFER my_fb2 AS resolve +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()); + + const auto* pipeline = pipelines[0].get(); + const auto& resolve_targets = pipeline->GetResolveTargets(); + ASSERT_EQ(3U, resolve_targets.size()); + + for (const auto& buf_info : resolve_targets) { + ASSERT_TRUE(buf_info.buffer != nullptr); + EXPECT_EQ(64u * 64u, buf_info.buffer->ElementCount()); + EXPECT_EQ(64u * 64u * 4u, buf_info.buffer->ValueCount()); + EXPECT_EQ(64u * 64u * 4u * sizeof(float), + buf_info.buffer->GetSizeInBytes()); + } +} + } // namespace amberscript } // namespace amber diff --git a/src/buffer.h b/src/buffer.h index 18f7fed..90f3b01 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -62,7 +62,9 @@ enum class BufferType : int8_t { /// A uniform texel buffer. kUniformTexelBuffer, /// A storage texel buffer. - kStorageTexelBuffer + kStorageTexelBuffer, + /// A resolve target. + kResolve }; enum class InputRate : int8_t { diff --git a/src/pipeline.cc b/src/pipeline.cc index 9b73041..ae3bf0a 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -389,6 +389,18 @@ Result Pipeline::AddColorAttachment(Buffer* buf, return {}; } +Result Pipeline::AddResolveTarget(Buffer* buf) { + resolve_targets_.push_back(BufferInfo{buf}); + + auto& info = resolve_targets_.back(); + info.type = BufferType::kResolve; + buf->SetWidth(fb_width_); + buf->SetHeight(fb_height_); + buf->SetElementCount(fb_width_ * fb_height_); + + return {}; +} + Result Pipeline::GetLocationForColorAttachment(Buffer* buf, uint32_t* loc) const { for (const auto& info : color_attachments_) { diff --git a/src/pipeline.h b/src/pipeline.h index 7a80ad4..9010c59 100644 --- a/src/pipeline.h +++ b/src/pipeline.h @@ -303,6 +303,14 @@ class Pipeline { /// something goes wrong. Result GetLocationForColorAttachment(Buffer* buf, uint32_t* loc) const; + /// Returns a list of all resolve targets in this pipeline. + const std::vector<BufferInfo>& GetResolveTargets() const { + return resolve_targets_; + } + + /// Adds |buf| as a multisample resolve target in the pipeline. + Result AddResolveTarget(Buffer* buf); + /// 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 @@ -436,6 +444,7 @@ class Pipeline { std::string name_; std::vector<ShaderInfo> shaders_; std::vector<BufferInfo> color_attachments_; + std::vector<BufferInfo> resolve_targets_; std::vector<BufferInfo> vertex_buffers_; std::vector<BufferInfo> buffers_; std::vector<std::unique_ptr<type::Type>> types_; diff --git a/src/vulkan/device.cc b/src/vulkan/device.cc index 72ad468..5e18277 100644 --- a/src/vulkan/device.cc +++ b/src/vulkan/device.cc @@ -840,6 +840,7 @@ bool Device::IsFormatSupportedByPhysicalDevice(const Format& format, bool is_buffer_type_image = false; switch (type) { case BufferType::kColor: + case BufferType::kResolve: case BufferType::kStorageImage: flag = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT; is_buffer_type_image = true; diff --git a/src/vulkan/engine_vulkan.cc b/src/vulkan/engine_vulkan.cc index 8d16545..1ed60f4 100644 --- a/src/vulkan/engine_vulkan.cc +++ b/src/vulkan/engine_vulkan.cc @@ -177,8 +177,8 @@ Result EngineVulkan::CreatePipeline(amber::Pipeline* pipeline) { } else { vk_pipeline = MakeUnique<GraphicsPipeline>( device_.get(), pipeline->GetColorAttachments(), - pipeline->GetDepthStencilBuffer(), engine_data.fence_timeout_ms, - stage_create_info); + pipeline->GetDepthStencilBuffer(), pipeline->GetResolveTargets(), + engine_data.fence_timeout_ms, stage_create_info); vk_pipeline->AsGraphics()->SetPatchControlPoints( pipeline->GetPipelineData()->GetPatchControlPoints()); diff --git a/src/vulkan/frame_buffer.cc b/src/vulkan/frame_buffer.cc index 70b8328..b6ad13a 100644 --- a/src/vulkan/frame_buffer.cc +++ b/src/vulkan/frame_buffer.cc @@ -30,10 +30,12 @@ FrameBuffer::FrameBuffer( Device* device, const std::vector<const amber::Pipeline::BufferInfo*>& color_attachments, amber::Pipeline::BufferInfo depth_stencil_attachment, + const std::vector<const amber::Pipeline::BufferInfo*>& resolve_targets, uint32_t width, uint32_t height) : device_(device), color_attachments_(color_attachments), + resolve_targets_(resolve_targets), depth_stencil_attachment_(depth_stencil_attachment), width_(width), height_(height) {} @@ -69,7 +71,7 @@ Result FrameBuffer::Initialize(VkRenderPass render_pass) { device_, *info->buffer->GetFormat(), VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_TYPE_2D, usage_flags, width_ << info->base_mip_level, height_ << info->base_mip_level, depth_, info->buffer->GetMipLevels(), - info->base_mip_level, 1u, 1u)); + info->base_mip_level, 1u, info->buffer->GetSamples())); Result r = color_images_.back()->Initialize(); if (!r.IsSuccess()) @@ -103,6 +105,22 @@ Result FrameBuffer::Initialize(VkRenderPass render_pass) { attachments.push_back(depth_stencil_image_->GetVkImageView()); } + for (auto* info : resolve_targets_) { + const VkImageUsageFlags usage_flags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + resolve_images_.push_back(MakeUnique<TransferImage>( + device_, *info->buffer->GetFormat(), VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_TYPE_2D, usage_flags, width_, height_, depth_, 1u, 0u, 1u, + 1u)); + + Result r = resolve_images_.back()->Initialize(); + if (!r.IsSuccess()) + return r; + + attachments.push_back(resolve_images_.back()->GetVkImageView()); + } + VkFramebufferCreateInfo frame_buffer_info = VkFramebufferCreateInfo(); frame_buffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; frame_buffer_info.renderPass = render_pass; @@ -129,6 +147,9 @@ void FrameBuffer::ChangeFrameLayout(CommandBuffer* command, for (auto& img : color_images_) img->ImageBarrier(command, color_layout, color_stage); + for (auto& img : resolve_images_) + img->ImageBarrier(command, color_layout, color_stage); + if (depth_stencil_image_) depth_stencil_image_->ImageBarrier(command, depth_layout, depth_stage); } @@ -165,6 +186,9 @@ void FrameBuffer::TransferImagesToHost(CommandBuffer* command) { for (auto& img : color_images_) img->CopyToHost(command); + for (auto& img : resolve_images_) + img->CopyToHost(command); + if (depth_stencil_image_) depth_stencil_image_->CopyToHost(command); } @@ -179,6 +203,15 @@ void FrameBuffer::CopyImagesToBuffers() { info->buffer->GetSizeInBytes()); } + for (size_t i = 0; i < resolve_images_.size(); ++i) { + auto& img = resolve_images_[i]; + auto* info = resolve_targets_[i]; + auto* values = info->buffer->ValuePtr(); + values->resize(info->buffer->GetSizeInBytes()); + 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()); @@ -208,6 +241,18 @@ void FrameBuffer::CopyBuffersToImages() { info->buffer->GetSizeInBytes()); } + for (size_t i = 0; i < resolve_images_.size(); ++i) { + auto& img = resolve_images_[i]; + auto* info = resolve_targets_[i]; + auto* values = info->buffer->ValuePtr(); + // Nothing to do if our local buffer is empty + if (values->empty()) + continue; + + 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 diff --git a/src/vulkan/frame_buffer.h b/src/vulkan/frame_buffer.h index 064b6d3..5774289 100644 --- a/src/vulkan/frame_buffer.h +++ b/src/vulkan/frame_buffer.h @@ -34,6 +34,7 @@ class FrameBuffer { Device* device, const std::vector<const amber::Pipeline::BufferInfo*>& color_attachments, amber::Pipeline::BufferInfo depth_stencil_attachment, + const std::vector<const amber::Pipeline::BufferInfo*>& resolve_targets, uint32_t width, uint32_t height); ~FrameBuffer(); @@ -70,9 +71,11 @@ class FrameBuffer { Device* device_ = nullptr; std::vector<const amber::Pipeline::BufferInfo*> color_attachments_; + std::vector<const amber::Pipeline::BufferInfo*> resolve_targets_; amber::Pipeline::BufferInfo depth_stencil_attachment_; VkFramebuffer frame_ = VK_NULL_HANDLE; std::vector<std::unique_ptr<TransferImage>> color_images_; + std::vector<std::unique_ptr<TransferImage>> resolve_images_; std::unique_ptr<TransferImage> depth_stencil_image_; uint32_t width_ = 0; uint32_t height_ = 0; diff --git a/src/vulkan/graphics_pipeline.cc b/src/vulkan/graphics_pipeline.cc index 5536440..9e3c7ac 100644 --- a/src/vulkan/graphics_pipeline.cc +++ b/src/vulkan/graphics_pipeline.cc @@ -386,6 +386,7 @@ GraphicsPipeline::GraphicsPipeline( Device* device, const std::vector<amber::Pipeline::BufferInfo>& color_buffers, amber::Pipeline::BufferInfo depth_stencil_buffer, + const std::vector<amber::Pipeline::BufferInfo>& resolve_targets, uint32_t fence_timeout_ms, const std::vector<VkPipelineShaderStageCreateInfo>& shader_stage_info) : Pipeline(PipelineType::kGraphics, @@ -395,6 +396,8 @@ GraphicsPipeline::GraphicsPipeline( depth_stencil_buffer_(depth_stencil_buffer) { for (const auto& info : color_buffers) color_buffers_.push_back(&info); + for (const auto& info : resolve_targets) + resolve_targets_.push_back(&info); } GraphicsPipeline::~GraphicsPipeline() { @@ -412,6 +415,7 @@ Result GraphicsPipeline::CreateRenderPass() { std::vector<VkAttachmentReference> color_refer; VkAttachmentReference depth_refer = VkAttachmentReference(); + std::vector<VkAttachmentReference> resolve_refer; for (const auto* info : color_buffers_) { attachment_desc.push_back(kDefaultAttachmentDesc); @@ -421,6 +425,8 @@ Result GraphicsPipeline::CreateRenderPass() { VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; attachment_desc.back().finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachment_desc.back().samples = + static_cast<VkSampleCountFlagBits>(info->buffer->GetSamples()); VkAttachmentReference ref = VkAttachmentReference(); ref.attachment = static_cast<uint32_t>(attachment_desc.size() - 1); @@ -446,6 +452,23 @@ Result GraphicsPipeline::CreateRenderPass() { subpass_desc.pDepthStencilAttachment = &depth_refer; } + for (const auto* info : resolve_targets_) { + attachment_desc.push_back(kDefaultAttachmentDesc); + attachment_desc.back().format = + device_->GetVkFormat(*info->buffer->GetFormat()); + attachment_desc.back().initialLayout = + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachment_desc.back().finalLayout = + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkAttachmentReference ref = VkAttachmentReference(); + ref.attachment = static_cast<uint32_t>(attachment_desc.size() - 1); + ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + resolve_refer.push_back(ref); + } + + subpass_desc.pResolveAttachments = resolve_refer.data(); + VkRenderPassCreateInfo render_pass_info = VkRenderPassCreateInfo(); render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; render_pass_info.attachmentCount = @@ -621,6 +644,16 @@ Result GraphicsPipeline::CreateVkGraphicsPipeline( VK_FALSE, /* alphaToOneEnable */ }; + // Search for multisampled color buffers and adjust the rasterization samples + // to match. + for (const auto& cb : color_buffers_) { + uint32_t samples = cb->buffer->GetSamples(); + assert(static_cast<VkSampleCountFlagBits>(samples) >= + multisampleInfo.rasterizationSamples); + multisampleInfo.rasterizationSamples = + static_cast<VkSampleCountFlagBits>(samples); + } + VkGraphicsPipelineCreateInfo pipeline_info = VkGraphicsPipelineCreateInfo(); pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; pipeline_info.stageCount = static_cast<uint32_t>(shader_stage_info.size()); @@ -704,8 +737,9 @@ Result GraphicsPipeline::Initialize(uint32_t width, if (!r.IsSuccess()) return r; - frame_ = MakeUnique<FrameBuffer>(device_, color_buffers_, - depth_stencil_buffer_, width, height); + frame_ = + MakeUnique<FrameBuffer>(device_, color_buffers_, depth_stencil_buffer_, + resolve_targets_, width, height); r = frame_->Initialize(render_pass_); if (!r.IsSuccess()) return r; diff --git a/src/vulkan/graphics_pipeline.h b/src/vulkan/graphics_pipeline.h index 7076231..cd55aad 100644 --- a/src/vulkan/graphics_pipeline.h +++ b/src/vulkan/graphics_pipeline.h @@ -43,6 +43,7 @@ class GraphicsPipeline : public Pipeline { Device* device, const std::vector<amber::Pipeline::BufferInfo>& color_buffers, amber::Pipeline::BufferInfo depth_stencil_buffer, + const std::vector<amber::Pipeline::BufferInfo>& resolve_targets, uint32_t fence_timeout_ms, const std::vector<VkPipelineShaderStageCreateInfo>&); ~GraphicsPipeline() override; @@ -86,8 +87,9 @@ class GraphicsPipeline : public Pipeline { VkRenderPass render_pass_ = VK_NULL_HANDLE; std::unique_ptr<FrameBuffer> frame_; - // color buffers are owned by the amber::Pipeline. + // color buffers and resolve targets are owned by the amber::Pipeline. std::vector<const amber::Pipeline::BufferInfo*> color_buffers_; + std::vector<const amber::Pipeline::BufferInfo*> resolve_targets_; amber::Pipeline::BufferInfo depth_stencil_buffer_; std::unique_ptr<IndexBuffer> index_buffer_; diff --git a/tests/cases/multisample_resolve.amber b/tests/cases/multisample_resolve.amber new file mode 100644 index 0000000..594f9bb --- /dev/null +++ b/tests/cases/multisample_resolve.amber @@ -0,0 +1,50 @@ +#!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. + +DEVICE_FEATURE sampleRateShading + +SHADER vertex vert_shader PASSTHROUGH + +SHADER fragment frag_shader GLSL +#version 440 +layout(location = 0) out vec4 color; + +void main (void) +{ + if (gl_SampleID == 0) + color = vec4(1, 0, 0, 1); + else if (gl_SampleID == 1) + color = vec4(0, 1, 0, 1); + else if (gl_SampleID == 2) + color = vec4(0, 0, 1, 1); + else + color = vec4(1, 1, 1, 1); +} +END + +IMAGE framebuffer_ms FORMAT R8G8B8A8_UNORM DIM_2D WIDTH 64 HEIGHT 64 SAMPLES 4 +IMAGE framebuffer FORMAT R8G8B8A8_UNORM DIM_2D WIDTH 64 HEIGHT 64 + +PIPELINE graphics pipeline + ATTACH vert_shader + ATTACH frag_shader + FRAMEBUFFER_SIZE 64 64 + BIND BUFFER framebuffer_ms AS color LOCATION 0 + BIND BUFFER framebuffer AS resolve +END + +RUN pipeline DRAW_RECT POS 0 0 SIZE 64 64 + +EXPECT framebuffer IDX 0 0 SIZE 64 64 EQ_RGBA 128 128 128 255 TOLERANCE 5% |