[Impeller] More sundry fixes to the Vulkan backend. (flutter/engine#40244)
[Impeller] More sundry fixes to the Vulkan backend.
This commit is contained in:
@@ -1409,10 +1409,18 @@ ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/command_buffer_vk.cc +
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/command_buffer_vk.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/command_encoder_vk.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/command_encoder_vk.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/command_pool_vk.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/command_pool_vk.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/context_vk.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/context_vk.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/debug_report_vk.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/debug_report_vk.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/descriptor_pool_vk.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/descriptor_pool_vk.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/device_buffer_vk.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/device_buffer_vk.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/fence_waiter_vk.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/fence_waiter_vk.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/formats_vk.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/formats_vk.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/pipeline_library_vk.cc + ../../../flutter/LICENSE
|
||||
@@ -1454,6 +1462,8 @@ ORIGIN: ../../../flutter/impeller/renderer/buffer.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/buffer.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/buffer_view.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/buffer_view.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/capabilities.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/capabilities.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/command.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/command.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/command_buffer.cc + ../../../flutter/LICENSE
|
||||
@@ -1468,13 +1478,10 @@ ORIGIN: ../../../flutter/impeller/renderer/compute_pipeline_descriptor.cc + ../.
|
||||
ORIGIN: ../../../flutter/impeller/renderer/compute_pipeline_descriptor.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/context.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/context.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/descriptor_set_layout.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/device_buffer.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/device_buffer.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/device_buffer_descriptor.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/device_buffer_descriptor.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/device_capabilities.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/device_capabilities.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/formats.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/formats.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/impeller/renderer/gpu_tracer.cc + ../../../flutter/LICENSE
|
||||
@@ -3936,10 +3943,18 @@ FILE: ../../../flutter/impeller/renderer/backend/vulkan/command_buffer_vk.cc
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/command_buffer_vk.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/command_encoder_vk.cc
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/command_encoder_vk.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/command_pool_vk.cc
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/command_pool_vk.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/context_vk.cc
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/context_vk.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/debug_report_vk.cc
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/debug_report_vk.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/descriptor_pool_vk.cc
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/descriptor_pool_vk.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/device_buffer_vk.cc
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/device_buffer_vk.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/fence_waiter_vk.cc
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/fence_waiter_vk.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/formats_vk.cc
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/formats_vk.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/pipeline_library_vk.cc
|
||||
@@ -3981,6 +3996,8 @@ FILE: ../../../flutter/impeller/renderer/buffer.cc
|
||||
FILE: ../../../flutter/impeller/renderer/buffer.h
|
||||
FILE: ../../../flutter/impeller/renderer/buffer_view.cc
|
||||
FILE: ../../../flutter/impeller/renderer/buffer_view.h
|
||||
FILE: ../../../flutter/impeller/renderer/capabilities.cc
|
||||
FILE: ../../../flutter/impeller/renderer/capabilities.h
|
||||
FILE: ../../../flutter/impeller/renderer/command.cc
|
||||
FILE: ../../../flutter/impeller/renderer/command.h
|
||||
FILE: ../../../flutter/impeller/renderer/command_buffer.cc
|
||||
@@ -3995,13 +4012,10 @@ FILE: ../../../flutter/impeller/renderer/compute_pipeline_descriptor.cc
|
||||
FILE: ../../../flutter/impeller/renderer/compute_pipeline_descriptor.h
|
||||
FILE: ../../../flutter/impeller/renderer/context.cc
|
||||
FILE: ../../../flutter/impeller/renderer/context.h
|
||||
FILE: ../../../flutter/impeller/renderer/descriptor_set_layout.h
|
||||
FILE: ../../../flutter/impeller/renderer/device_buffer.cc
|
||||
FILE: ../../../flutter/impeller/renderer/device_buffer.h
|
||||
FILE: ../../../flutter/impeller/renderer/device_buffer_descriptor.cc
|
||||
FILE: ../../../flutter/impeller/renderer/device_buffer_descriptor.h
|
||||
FILE: ../../../flutter/impeller/renderer/device_capabilities.cc
|
||||
FILE: ../../../flutter/impeller/renderer/device_capabilities.h
|
||||
FILE: ../../../flutter/impeller/renderer/formats.cc
|
||||
FILE: ../../../flutter/impeller/renderer/formats.h
|
||||
FILE: ../../../flutter/impeller/renderer/gpu_tracer.cc
|
||||
|
||||
@@ -108,7 +108,7 @@ bool GenerateMipmap(const std::shared_ptr<Context>& context,
|
||||
}
|
||||
pass->GenerateMipmap(std::move(texture), std::move(label));
|
||||
pass->EncodeCommands(context->GetResourceAllocator());
|
||||
return true;
|
||||
return buffer->SubmitCommands();
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanRenderTiledTexture) {
|
||||
|
||||
@@ -54,7 +54,7 @@ std::shared_ptr<Texture> Picture::RenderToTexture(
|
||||
// features to Image someday.
|
||||
auto impeller_context = context.GetContext();
|
||||
RenderTarget target;
|
||||
if (impeller_context->GetDeviceCapabilities().SupportsOffscreenMSAA()) {
|
||||
if (impeller_context->GetCapabilities()->SupportsOffscreenMSAA()) {
|
||||
target = RenderTarget::CreateOffscreenMSAA(*impeller_context, size);
|
||||
} else {
|
||||
target = RenderTarget::CreateOffscreen(*impeller_context, size);
|
||||
|
||||
@@ -22,8 +22,6 @@ constexpr std::string_view kReflectionHeaderTemplate =
|
||||
|
||||
#include "impeller/renderer/compute_command.h" {# // nogncheck #}
|
||||
|
||||
#include "impeller/renderer/descriptor_set_layout.h" {# // nogncheck #}
|
||||
|
||||
#include "impeller/renderer/sampler.h" {# // nogncheck #}
|
||||
|
||||
#include "impeller/renderer/shader_types.h" {# // nogncheck #}
|
||||
@@ -166,17 +164,15 @@ std::move({{ arg.argument_name }}){% if not loop.is_last %}, {% endif %}
|
||||
{% for buffer in buffers %}
|
||||
DescriptorSetLayout{
|
||||
{{buffer.binding}}, // binding = {{buffer.binding}}
|
||||
DescriptorType::kUniformBuffer, // descriptorType = Uniform Buffer
|
||||
1, // descriptorCount = 1
|
||||
{{to_shader_stage(shader_stage)}}, // stageFlags = {{to_shader_stage(shader_stage)}}
|
||||
DescriptorType::kUniformBuffer, // descriptor_type = Uniform Buffer
|
||||
{{to_shader_stage(shader_stage)}}, // shader_stage = {{to_shader_stage(shader_stage)}}
|
||||
},
|
||||
{% endfor %}
|
||||
{% for sampled_image in sampled_images %}
|
||||
DescriptorSetLayout{
|
||||
{{sampled_image.binding}}, // binding = {{sampled_image.binding}}
|
||||
DescriptorType::kSampledImage, // descriptorType = Sampled Image
|
||||
1, // descriptorCount = 1
|
||||
{{to_shader_stage(shader_stage)}}, // stageFlags = {{to_shader_stage(shader_stage)}}
|
||||
DescriptorType::kSampledImage, // descriptor_type = Sampled Image
|
||||
{{to_shader_stage(shader_stage)}}, // shader_stage = {{to_shader_stage(shader_stage)}}
|
||||
},
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
@@ -154,7 +154,8 @@ static std::unique_ptr<PipelineT> CreateDefaultPipeline(
|
||||
return nullptr;
|
||||
}
|
||||
// Apply default ContentContextOptions to the descriptor.
|
||||
const auto default_color_fmt = context.GetColorAttachmentPixelFormat();
|
||||
const auto default_color_fmt =
|
||||
context.GetCapabilities()->GetDefaultColorFormat();
|
||||
ContentContextOptions{.color_attachment_pixel_format = default_color_fmt}
|
||||
.ApplyToPipelineDescriptor(*desc);
|
||||
return std::make_unique<PipelineT>(context, desc);
|
||||
@@ -175,7 +176,7 @@ ContentContext::ContentContext(std::shared_ptr<Context> context)
|
||||
CreateDefaultPipeline<LinearGradientFillPipeline>(*context_);
|
||||
radial_gradient_fill_pipelines_[{}] =
|
||||
CreateDefaultPipeline<RadialGradientFillPipeline>(*context_);
|
||||
if (context_->GetDeviceCapabilities().SupportsSSBO()) {
|
||||
if (context_->GetCapabilities()->SupportsSSBO()) {
|
||||
linear_gradient_ssbo_fill_pipelines_[{}] =
|
||||
CreateDefaultPipeline<LinearGradientSSBOFillPipeline>(*context_);
|
||||
radial_gradient_ssbo_fill_pipelines_[{}] =
|
||||
@@ -183,7 +184,7 @@ ContentContext::ContentContext(std::shared_ptr<Context> context)
|
||||
sweep_gradient_ssbo_fill_pipelines_[{}] =
|
||||
CreateDefaultPipeline<SweepGradientSSBOFillPipeline>(*context_);
|
||||
}
|
||||
if (context_->GetDeviceCapabilities().SupportsFramebufferFetch()) {
|
||||
if (context_->GetCapabilities()->SupportsFramebufferFetch()) {
|
||||
framebuffer_blend_color_pipelines_[{}] =
|
||||
CreateDefaultPipeline<FramebufferBlendColorPipeline>(*context_);
|
||||
framebuffer_blend_colorburn_pipelines_[{}] =
|
||||
@@ -315,8 +316,7 @@ std::shared_ptr<Texture> ContentContext::MakeSubpass(
|
||||
auto context = GetContext();
|
||||
|
||||
RenderTarget subpass_target;
|
||||
if (context->GetDeviceCapabilities().SupportsOffscreenMSAA() &&
|
||||
msaa_enabled) {
|
||||
if (context->GetCapabilities()->SupportsOffscreenMSAA() && msaa_enabled) {
|
||||
subpass_target = RenderTarget::CreateOffscreenMSAA(
|
||||
*context, texture_size, SPrintF("%s Offscreen", label.c_str()),
|
||||
RenderTarget::kDefaultColorAttachmentConfigMSAA, std::nullopt);
|
||||
@@ -374,8 +374,8 @@ std::shared_ptr<Context> ContentContext::GetContext() const {
|
||||
return context_;
|
||||
}
|
||||
|
||||
const IDeviceCapabilities& ContentContext::GetDeviceCapabilities() const {
|
||||
return context_->GetDeviceCapabilities();
|
||||
const Capabilities& ContentContext::GetDeviceCapabilities() const {
|
||||
return *context_->GetCapabilities();
|
||||
}
|
||||
|
||||
void ContentContext::SetWireframe(bool wireframe) {
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
#include "impeller/entity/vertices.frag.h"
|
||||
#include "impeller/entity/yuv_to_rgb_filter.frag.h"
|
||||
#include "impeller/entity/yuv_to_rgb_filter.vert.h"
|
||||
#include "impeller/renderer/device_capabilities.h"
|
||||
#include "impeller/renderer/capabilities.h"
|
||||
#include "impeller/renderer/formats.h"
|
||||
#include "impeller/renderer/pipeline.h"
|
||||
#include "impeller/scene/scene_context.h"
|
||||
@@ -601,7 +601,7 @@ class ContentContext {
|
||||
|
||||
std::shared_ptr<GlyphAtlasContext> GetGlyphAtlasContext() const;
|
||||
|
||||
const IDeviceCapabilities& GetDeviceCapabilities() const;
|
||||
const Capabilities& GetDeviceCapabilities() const;
|
||||
|
||||
void SetWireframe(bool wireframe);
|
||||
|
||||
|
||||
@@ -102,10 +102,9 @@ bool RuntimeEffectContents::Render(const ContentContext& renderer,
|
||||
/// Get or create runtime stage pipeline.
|
||||
///
|
||||
|
||||
const auto& device_capabilities = context->GetDeviceCapabilities();
|
||||
const auto color_attachment_format = context->GetColorAttachmentPixelFormat();
|
||||
const auto stencil_attachment_format =
|
||||
device_capabilities.GetDefaultStencilFormat();
|
||||
const auto& caps = context->GetCapabilities();
|
||||
const auto color_attachment_format = caps->GetDefaultColorFormat();
|
||||
const auto stencil_attachment_format = caps->GetDefaultStencilFormat();
|
||||
|
||||
using VS = RuntimeEffectVertexShader;
|
||||
PipelineDescriptor desc;
|
||||
|
||||
@@ -152,7 +152,7 @@ static RenderTarget CreateRenderTarget(ContentContext& renderer,
|
||||
/// What's important is the `StorageMode` of the textures, which cannot be
|
||||
/// changed for the lifetime of the textures.
|
||||
|
||||
if (context->GetDeviceCapabilities().SupportsOffscreenMSAA()) {
|
||||
if (context->GetCapabilities()->SupportsOffscreenMSAA()) {
|
||||
return RenderTarget::CreateOffscreenMSAA(
|
||||
*context, // context
|
||||
size, // size
|
||||
@@ -210,8 +210,8 @@ bool EntityPass::Render(ContentContext& renderer,
|
||||
command_buffer->SetLabel("EntityPass Root Command Buffer");
|
||||
|
||||
if (renderer.GetContext()
|
||||
->GetDeviceCapabilities()
|
||||
.SupportsTextureToTextureBlits()) {
|
||||
->GetCapabilities()
|
||||
->SupportsTextureToTextureBlits()) {
|
||||
auto blit_pass = command_buffer->CreateBlitPass();
|
||||
|
||||
blit_pass->AddCopy(offscreen_target.GetRenderTargetTexture(),
|
||||
|
||||
@@ -82,9 +82,8 @@ PlaygroundImplMTL::PlaygroundImplMTL()
|
||||
}
|
||||
data_->metal_layer = [CAMetalLayer layer];
|
||||
data_->metal_layer.device = ContextMTL::Cast(*context).GetMTLDevice();
|
||||
// This pixel format is one of the documented supported formats.
|
||||
const auto color_fmt = context->GetColorAttachmentPixelFormat();
|
||||
data_->metal_layer.pixelFormat = ToMTLPixelFormat(color_fmt);
|
||||
data_->metal_layer.pixelFormat =
|
||||
ToMTLPixelFormat(context->GetCapabilities()->GetDefaultColorFormat());
|
||||
data_->metal_layer.framebufferOnly = NO;
|
||||
cocoa_window.contentView.layer = data_->metal_layer;
|
||||
cocoa_window.contentView.wantsLayer = YES;
|
||||
|
||||
@@ -402,8 +402,13 @@ std::shared_ptr<Texture> Playground::CreateTextureForFixture(
|
||||
std::shared_ptr<Texture> Playground::CreateTextureForFixture(
|
||||
const char* fixture_name,
|
||||
bool enable_mipmapping) const {
|
||||
return CreateTextureForFixture(OpenAssetAsMapping(fixture_name),
|
||||
enable_mipmapping);
|
||||
auto texture = CreateTextureForFixture(OpenAssetAsMapping(fixture_name),
|
||||
enable_mipmapping);
|
||||
if (texture == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
texture->SetLabel(fixture_name);
|
||||
return texture;
|
||||
}
|
||||
|
||||
std::shared_ptr<Texture> Playground::CreateTextureCubeForFixture(
|
||||
|
||||
@@ -16,6 +16,8 @@ impeller_component("renderer") {
|
||||
"buffer.h",
|
||||
"buffer_view.cc",
|
||||
"buffer_view.h",
|
||||
"capabilities.cc",
|
||||
"capabilities.h",
|
||||
"command.cc",
|
||||
"command.h",
|
||||
"command_buffer.cc",
|
||||
@@ -30,13 +32,10 @@ impeller_component("renderer") {
|
||||
"compute_pipeline_descriptor.h",
|
||||
"context.cc",
|
||||
"context.h",
|
||||
"descriptor_set_layout.h",
|
||||
"device_buffer.cc",
|
||||
"device_buffer.h",
|
||||
"device_buffer_descriptor.cc",
|
||||
"device_buffer_descriptor.h",
|
||||
"device_capabilities.cc",
|
||||
"device_capabilities.h",
|
||||
"formats.cc",
|
||||
"formats.h",
|
||||
"gpu_tracer.cc",
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "impeller/base/config.h"
|
||||
#include "impeller/base/validation.h"
|
||||
#include "impeller/base/work_queue_common.h"
|
||||
#include "impeller/renderer/device_capabilities.h"
|
||||
#include "impeller/renderer/capabilities.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
@@ -72,7 +72,7 @@ ContextGLES::ContextGLES(std::unique_ptr<ProcTableGLES> gl,
|
||||
// Create the device capabilities.
|
||||
{
|
||||
device_capabilities_ =
|
||||
DeviceCapabilitiesBuilder()
|
||||
CapabilitiesBuilder()
|
||||
.SetHasThreadingRestrictions(true)
|
||||
.SetSupportsOffscreenMSAA(false)
|
||||
.SetSupportsSSBO(false)
|
||||
@@ -145,13 +145,9 @@ std::shared_ptr<WorkQueue> ContextGLES::GetWorkQueue() const {
|
||||
}
|
||||
|
||||
// |Context|
|
||||
const IDeviceCapabilities& ContextGLES::GetDeviceCapabilities() const {
|
||||
return *device_capabilities_;
|
||||
}
|
||||
|
||||
// |Context|
|
||||
PixelFormat ContextGLES::GetColorAttachmentPixelFormat() const {
|
||||
return PixelFormat::kR8G8B8A8UNormInt;
|
||||
const std::shared_ptr<const Capabilities>& ContextGLES::GetCapabilities()
|
||||
const {
|
||||
return device_capabilities_;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
#include "impeller/renderer/backend/gles/reactor_gles.h"
|
||||
#include "impeller/renderer/backend/gles/sampler_library_gles.h"
|
||||
#include "impeller/renderer/backend/gles/shader_library_gles.h"
|
||||
#include "impeller/renderer/capabilities.h"
|
||||
#include "impeller/renderer/context.h"
|
||||
#include "impeller/renderer/device_capabilities.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
@@ -41,7 +41,7 @@ class ContextGLES final : public Context,
|
||||
std::shared_ptr<SamplerLibraryGLES> sampler_library_;
|
||||
std::shared_ptr<WorkQueue> work_queue_;
|
||||
std::shared_ptr<AllocatorGLES> resource_allocator_;
|
||||
std::unique_ptr<IDeviceCapabilities> device_capabilities_;
|
||||
std::shared_ptr<const Capabilities> device_capabilities_;
|
||||
bool is_valid_ = false;
|
||||
|
||||
ContextGLES(
|
||||
@@ -70,10 +70,7 @@ class ContextGLES final : public Context,
|
||||
std::shared_ptr<WorkQueue> GetWorkQueue() const override;
|
||||
|
||||
// |Context|
|
||||
const IDeviceCapabilities& GetDeviceCapabilities() const override;
|
||||
|
||||
// |Context|
|
||||
PixelFormat GetColorAttachmentPixelFormat() const override;
|
||||
const std::shared_ptr<const Capabilities>& GetCapabilities() const override;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(ContextGLES);
|
||||
};
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
#include "impeller/renderer/backend/metal/gpu_tracer_mtl.h"
|
||||
#include "impeller/renderer/backend/metal/pipeline_library_mtl.h"
|
||||
#include "impeller/renderer/backend/metal/shader_library_mtl.h"
|
||||
#include "impeller/renderer/capabilities.h"
|
||||
#include "impeller/renderer/context.h"
|
||||
#include "impeller/renderer/device_capabilities.h"
|
||||
#include "impeller/renderer/sampler.h"
|
||||
|
||||
namespace impeller {
|
||||
@@ -37,22 +37,6 @@ class ContextMTL final : public Context,
|
||||
|
||||
id<MTLDevice> GetMTLDevice() const;
|
||||
|
||||
private:
|
||||
id<MTLDevice> device_ = nullptr;
|
||||
id<MTLCommandQueue> command_queue_ = nullptr;
|
||||
std::shared_ptr<ShaderLibraryMTL> shader_library_;
|
||||
std::shared_ptr<PipelineLibraryMTL> pipeline_library_;
|
||||
std::shared_ptr<SamplerLibrary> sampler_library_;
|
||||
std::shared_ptr<AllocatorMTL> resource_allocator_;
|
||||
std::shared_ptr<WorkQueue> work_queue_;
|
||||
std::shared_ptr<GPUTracerMTL> gpu_tracer_;
|
||||
std::unique_ptr<IDeviceCapabilities> device_capabilities_;
|
||||
bool is_valid_ = false;
|
||||
|
||||
ContextMTL(id<MTLDevice> device, NSArray<id<MTLLibrary>>* shader_libraries);
|
||||
|
||||
bool SupportsFramebufferFetch() const;
|
||||
|
||||
// |Context|
|
||||
bool IsValid() const override;
|
||||
|
||||
@@ -78,7 +62,24 @@ class ContextMTL final : public Context,
|
||||
std::shared_ptr<GPUTracer> GetGPUTracer() const override;
|
||||
|
||||
// |Context|
|
||||
const IDeviceCapabilities& GetDeviceCapabilities() const override;
|
||||
const std::shared_ptr<const Capabilities>& GetCapabilities() const override;
|
||||
|
||||
// |Context|
|
||||
bool UpdateOffscreenLayerPixelFormat(PixelFormat format) override;
|
||||
|
||||
private:
|
||||
id<MTLDevice> device_ = nullptr;
|
||||
id<MTLCommandQueue> command_queue_ = nullptr;
|
||||
std::shared_ptr<ShaderLibraryMTL> shader_library_;
|
||||
std::shared_ptr<PipelineLibraryMTL> pipeline_library_;
|
||||
std::shared_ptr<SamplerLibrary> sampler_library_;
|
||||
std::shared_ptr<AllocatorMTL> resource_allocator_;
|
||||
std::shared_ptr<WorkQueue> work_queue_;
|
||||
std::shared_ptr<GPUTracerMTL> gpu_tracer_;
|
||||
std::shared_ptr<const Capabilities> device_capabilities_;
|
||||
bool is_valid_ = false;
|
||||
|
||||
ContextMTL(id<MTLDevice> device, NSArray<id<MTLLibrary>>* shader_libraries);
|
||||
|
||||
std::shared_ptr<CommandBuffer> CreateCommandBufferInQueue(
|
||||
id<MTLCommandQueue> queue) const;
|
||||
|
||||
@@ -11,11 +11,56 @@
|
||||
#include "flutter/fml/paths.h"
|
||||
#include "impeller/base/platform/darwin/work_queue_darwin.h"
|
||||
#include "impeller/renderer/backend/metal/sampler_library_mtl.h"
|
||||
#include "impeller/renderer/device_capabilities.h"
|
||||
#include "impeller/renderer/capabilities.h"
|
||||
#include "impeller/renderer/sampler_descriptor.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
static bool DeviceSupportsFramebufferFetch(id<MTLDevice> device) {
|
||||
// The iOS simulator lies about supporting framebuffer fetch.
|
||||
#if FML_OS_IOS_SIMULATOR
|
||||
return false;
|
||||
#endif // FML_OS_IOS_SIMULATOR
|
||||
|
||||
if (@available(macOS 10.15, iOS 13, tvOS 13, *)) {
|
||||
return [device supportsFamily:MTLGPUFamilyApple2];
|
||||
}
|
||||
// According to
|
||||
// https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf , Apple2
|
||||
// corresponds to iOS GPU family 2, which supports A8 devices.
|
||||
#if FML_OS_IOS
|
||||
return [device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v1];
|
||||
#else
|
||||
return false;
|
||||
#endif // FML_OS_IOS
|
||||
}
|
||||
|
||||
static bool DeviceSupportsComputeSubgroups(id<MTLDevice> device) {
|
||||
bool supports_subgroups = false;
|
||||
// Refer to the "SIMD-scoped reduction operations" feature in the table
|
||||
// below: https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
|
||||
if (@available(ios 13.0, tvos 13.0, macos 10.15, *)) {
|
||||
supports_subgroups = [device supportsFamily:MTLGPUFamilyApple7] ||
|
||||
[device supportsFamily:MTLGPUFamilyMac2];
|
||||
}
|
||||
return supports_subgroups;
|
||||
}
|
||||
|
||||
static std::unique_ptr<Capabilities> InferMetalCapabilities(
|
||||
id<MTLDevice> device,
|
||||
PixelFormat color_format = PixelFormat::kB8G8R8A8UNormInt) {
|
||||
return CapabilitiesBuilder()
|
||||
.SetHasThreadingRestrictions(false)
|
||||
.SetSupportsOffscreenMSAA(true)
|
||||
.SetSupportsSSBO(true)
|
||||
.SetSupportsTextureToTextureBlits(true)
|
||||
.SetSupportsFramebufferFetch(DeviceSupportsFramebufferFetch(device))
|
||||
.SetDefaultColorFormat(color_format)
|
||||
.SetDefaultStencilFormat(PixelFormat::kS8UInt)
|
||||
.SetSupportsCompute(true, DeviceSupportsComputeSubgroups(device))
|
||||
.Build();
|
||||
}
|
||||
|
||||
ContextMTL::ContextMTL(id<MTLDevice> device,
|
||||
NSArray<id<MTLLibrary>>* shader_libraries)
|
||||
: device_(device) {
|
||||
@@ -89,50 +134,11 @@ ContextMTL::ContextMTL(id<MTLDevice> device,
|
||||
{ gpu_tracer_ = std::shared_ptr<GPUTracerMTL>(new GPUTracerMTL(device_)); }
|
||||
#endif
|
||||
|
||||
{
|
||||
bool supports_subgroups = false;
|
||||
// Refer to the "SIMD-scoped reduction operations" feature in the table
|
||||
// below: https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
|
||||
if (@available(ios 13.0, tvos 13.0, macos 10.15, *)) {
|
||||
supports_subgroups = [device supportsFamily:MTLGPUFamilyApple7] ||
|
||||
[device supportsFamily:MTLGPUFamilyMac2];
|
||||
}
|
||||
|
||||
device_capabilities_ =
|
||||
DeviceCapabilitiesBuilder()
|
||||
.SetHasThreadingRestrictions(false)
|
||||
.SetSupportsOffscreenMSAA(true)
|
||||
.SetSupportsSSBO(true)
|
||||
.SetSupportsTextureToTextureBlits(true)
|
||||
.SetSupportsFramebufferFetch(SupportsFramebufferFetch())
|
||||
.SetDefaultColorFormat(PixelFormat::kB8G8R8A8UNormInt)
|
||||
.SetDefaultStencilFormat(PixelFormat::kS8UInt)
|
||||
.SetSupportsCompute(true, supports_subgroups)
|
||||
.Build();
|
||||
}
|
||||
device_capabilities_ = InferMetalCapabilities(device_);
|
||||
|
||||
is_valid_ = true;
|
||||
}
|
||||
|
||||
bool ContextMTL::SupportsFramebufferFetch() const {
|
||||
// The iOS simulator lies about supporting framebuffer fetch.
|
||||
#if FML_OS_IOS_SIMULATOR
|
||||
return false;
|
||||
#endif // FML_OS_IOS_SIMULATOR
|
||||
|
||||
if (@available(macOS 10.15, iOS 13, tvOS 13, *)) {
|
||||
return [device_ supportsFamily:MTLGPUFamilyApple2];
|
||||
}
|
||||
// According to
|
||||
// https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf , Apple2
|
||||
// corresponds to iOS GPU family 2, which supports A8 devices.
|
||||
#if FML_OS_IOS
|
||||
return [device_ supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v1];
|
||||
#else
|
||||
return false;
|
||||
#endif // FML_OS_IOS
|
||||
}
|
||||
|
||||
static NSArray<id<MTLLibrary>>* MTLShaderLibraryFromFilePaths(
|
||||
id<MTLDevice> device,
|
||||
const std::vector<std::string>& libraries_paths) {
|
||||
@@ -287,8 +293,14 @@ id<MTLDevice> ContextMTL::GetMTLDevice() const {
|
||||
return device_;
|
||||
}
|
||||
|
||||
const IDeviceCapabilities& ContextMTL::GetDeviceCapabilities() const {
|
||||
return *device_capabilities_;
|
||||
const std::shared_ptr<const Capabilities>& ContextMTL::GetCapabilities() const {
|
||||
return device_capabilities_;
|
||||
}
|
||||
|
||||
// |Context|
|
||||
bool ContextMTL::UpdateOffscreenLayerPixelFormat(PixelFormat format) {
|
||||
device_capabilities_ = InferMetalCapabilities(device_);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@@ -64,6 +64,7 @@ std::unique_ptr<SurfaceMTL> SurfaceMTL::WrapCurrentMetalLayerDrawable(
|
||||
resolve_tex_desc.format = color_format;
|
||||
resolve_tex_desc.size = msaa_tex_desc.size;
|
||||
resolve_tex_desc.usage = static_cast<uint64_t>(TextureUsage::kRenderTarget);
|
||||
resolve_tex_desc.sample_count = SampleCount::kCount1;
|
||||
resolve_tex_desc.storage_mode = StorageMode::kDevicePrivate;
|
||||
|
||||
std::shared_ptr<Texture> resolve_tex =
|
||||
@@ -86,7 +87,7 @@ std::unique_ptr<SurfaceMTL> SurfaceMTL::WrapCurrentMetalLayerDrawable(
|
||||
stencil_tex_desc.type = TextureType::kTexture2DMultisample;
|
||||
stencil_tex_desc.sample_count = SampleCount::kCount4;
|
||||
stencil_tex_desc.format =
|
||||
context->GetDeviceCapabilities().GetDefaultStencilFormat();
|
||||
context->GetCapabilities()->GetDefaultStencilFormat();
|
||||
stencil_tex_desc.size = msaa_tex_desc.size;
|
||||
stencil_tex_desc.usage =
|
||||
static_cast<TextureUsageMask>(TextureUsage::kRenderTarget);
|
||||
|
||||
@@ -18,10 +18,18 @@ impeller_component("vulkan") {
|
||||
"command_buffer_vk.h",
|
||||
"command_encoder_vk.cc",
|
||||
"command_encoder_vk.h",
|
||||
"command_pool_vk.cc",
|
||||
"command_pool_vk.h",
|
||||
"context_vk.cc",
|
||||
"context_vk.h",
|
||||
"debug_report_vk.cc",
|
||||
"debug_report_vk.h",
|
||||
"descriptor_pool_vk.cc",
|
||||
"descriptor_pool_vk.h",
|
||||
"device_buffer_vk.cc",
|
||||
"device_buffer_vk.h",
|
||||
"fence_waiter_vk.cc",
|
||||
"fence_waiter_vk.h",
|
||||
"formats_vk.cc",
|
||||
"formats_vk.h",
|
||||
"pipeline_library_vk.cc",
|
||||
|
||||
@@ -152,10 +152,12 @@ static constexpr vk::ImageUsageFlags ToVKImageUsageFlags(PixelFormat format,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO (https://github.com/flutter/flutter/issues/121634):
|
||||
// Add transfer usage flags to support blit passes
|
||||
vk_usage |= vk::ImageUsageFlagBits::eTransferSrc |
|
||||
vk::ImageUsageFlagBits::eTransferDst;
|
||||
if (mode != StorageMode::kDeviceTransient) {
|
||||
// TODO (https://github.com/flutter/flutter/issues/121634):
|
||||
// Add transfer usage flags to support blit passes
|
||||
vk_usage |= vk::ImageUsageFlagBits::eTransferSrc |
|
||||
vk::ImageUsageFlagBits::eTransferDst;
|
||||
}
|
||||
|
||||
return vk_usage;
|
||||
}
|
||||
@@ -211,8 +213,10 @@ class AllocatedTextureSourceVK final : public TextureSourceVK {
|
||||
public:
|
||||
AllocatedTextureSourceVK(const TextureDescriptor& desc,
|
||||
VmaAllocator allocator,
|
||||
vk::Device device) {
|
||||
vk::Device device)
|
||||
: TextureSourceVK(desc) {
|
||||
vk::ImageCreateInfo image_info;
|
||||
image_info.flags = ToVKImageCreateFlags(desc.type);
|
||||
image_info.imageType = vk::ImageType::e2D;
|
||||
image_info.format = ToVKImageFormat(desc.format);
|
||||
image_info.extent = VkExtent3D{
|
||||
@@ -229,13 +233,11 @@ class AllocatedTextureSourceVK final : public TextureSourceVK {
|
||||
ToVKImageUsageFlags(desc.format, desc.usage, desc.storage_mode);
|
||||
image_info.sharingMode = vk::SharingMode::eExclusive;
|
||||
|
||||
VmaAllocationCreateInfo alloc_create_info = {};
|
||||
VmaAllocationCreateInfo alloc_nfo = {};
|
||||
|
||||
alloc_create_info.usage = ToVMAMemoryUsage();
|
||||
alloc_create_info.preferredFlags =
|
||||
ToVKMemoryPropertyFlags(desc.storage_mode, true);
|
||||
alloc_create_info.flags =
|
||||
ToVmaAllocationCreateFlags(desc.storage_mode, true);
|
||||
alloc_nfo.usage = ToVMAMemoryUsage();
|
||||
alloc_nfo.preferredFlags = ToVKMemoryPropertyFlags(desc.storage_mode, true);
|
||||
alloc_nfo.flags = ToVmaAllocationCreateFlags(desc.storage_mode, true);
|
||||
|
||||
auto create_info_native =
|
||||
static_cast<vk::ImageCreateInfo::NativeType>(image_info);
|
||||
@@ -244,13 +246,13 @@ class AllocatedTextureSourceVK final : public TextureSourceVK {
|
||||
VmaAllocation allocation = {};
|
||||
VmaAllocationInfo allocation_info = {};
|
||||
{
|
||||
auto result = vk::Result{vmaCreateImage(allocator, //
|
||||
&create_info_native, //
|
||||
&alloc_create_info, //
|
||||
&vk_image, //
|
||||
&allocation, //
|
||||
&allocation_info //
|
||||
)};
|
||||
auto result = vk::Result{::vmaCreateImage(allocator, //
|
||||
&create_info_native, //
|
||||
&alloc_nfo, //
|
||||
&vk_image, //
|
||||
&allocation, //
|
||||
&allocation_info //
|
||||
)};
|
||||
if (result != vk::Result::eSuccess) {
|
||||
VALIDATION_LOG << "Unable to allocate Vulkan Image: "
|
||||
<< vk::to_string(result);
|
||||
@@ -262,25 +264,24 @@ class AllocatedTextureSourceVK final : public TextureSourceVK {
|
||||
allocator_ = allocator;
|
||||
allocation_ = allocation;
|
||||
|
||||
vk::ImageViewCreateInfo view_create_info = {};
|
||||
view_create_info.image = image_;
|
||||
view_create_info.viewType = vk::ImageViewType::e2D;
|
||||
view_create_info.format = image_info.format;
|
||||
view_create_info.subresourceRange.aspectMask =
|
||||
ToVKImageAspectFlags(desc.format);
|
||||
view_create_info.subresourceRange.levelCount = image_info.mipLevels;
|
||||
view_create_info.subresourceRange.layerCount = 1u;
|
||||
vk::ImageViewCreateInfo view_info = {};
|
||||
view_info.image = image_;
|
||||
view_info.viewType = ToVKImageViewType(desc.type);
|
||||
view_info.format = image_info.format;
|
||||
view_info.subresourceRange.aspectMask = ToVKImageAspectFlags(desc.format);
|
||||
view_info.subresourceRange.levelCount = image_info.mipLevels;
|
||||
view_info.subresourceRange.layerCount = ToArrayLayerCount(desc.type);
|
||||
|
||||
// Vulkan does not have an image format that is equivalent to
|
||||
// `MTLPixelFormatA8Unorm`, so we use `R8Unorm` instead. Given that the
|
||||
// shaders expect that alpha channel to be set in the cases, we swizzle.
|
||||
// See: https://github.com/flutter/flutter/issues/115461 for more details.
|
||||
if (desc.format == PixelFormat::kA8UNormInt) {
|
||||
view_create_info.components.a = vk::ComponentSwizzle::eR;
|
||||
view_create_info.components.r = vk::ComponentSwizzle::eA;
|
||||
view_info.components.a = vk::ComponentSwizzle::eR;
|
||||
view_info.components.r = vk::ComponentSwizzle::eA;
|
||||
}
|
||||
|
||||
auto [result, image_view] = device.createImageViewUnique(view_create_info);
|
||||
auto [result, image_view] = device.createImageViewUnique(view_info);
|
||||
if (result != vk::Result::eSuccess) {
|
||||
VALIDATION_LOG << "Unable to create an image view for allocation: "
|
||||
<< vk::to_string(result);
|
||||
@@ -294,7 +295,7 @@ class AllocatedTextureSourceVK final : public TextureSourceVK {
|
||||
~AllocatedTextureSourceVK() {
|
||||
image_view_.reset();
|
||||
if (image_) {
|
||||
vmaDestroyImage(
|
||||
::vmaDestroyImage(
|
||||
allocator_, //
|
||||
static_cast<typename decltype(image_)::NativeType>(image_), //
|
||||
allocation_ //
|
||||
@@ -335,9 +336,9 @@ class AllocatedTextureSourceVK final : public TextureSourceVK {
|
||||
|
||||
bool IsValid() const { return is_valid_; }
|
||||
|
||||
vk::Image GetVKImage() const override { return image_; }
|
||||
vk::Image GetImage() const override { return image_; }
|
||||
|
||||
vk::ImageView GetVKImageView() const override { return image_view_.get(); }
|
||||
vk::ImageView GetImageView() const override { return image_view_.get(); }
|
||||
|
||||
private:
|
||||
vk::Image image_ = {};
|
||||
@@ -362,7 +363,7 @@ std::shared_ptr<Texture> AllocatorVK::OnCreateTexture(
|
||||
if (!source->IsValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
return std::make_shared<TextureVK>(desc, context_, std::move(source));
|
||||
return std::make_shared<TextureVK>(context_, std::move(source));
|
||||
}
|
||||
|
||||
// |Allocator|
|
||||
|
||||
@@ -28,7 +28,7 @@ class AllocatorVK final : public Allocator {
|
||||
VmaAllocator allocator_ = {};
|
||||
std::weak_ptr<Context> context_;
|
||||
vk::Device device_;
|
||||
ISize max_texture_size_ = {4096, 4096};
|
||||
ISize max_texture_size_;
|
||||
bool is_valid_ = false;
|
||||
|
||||
AllocatorVK(std::weak_ptr<Context> context,
|
||||
|
||||
@@ -29,11 +29,27 @@ bool BlitCopyTextureToTextureCommandVK::Encode(
|
||||
const auto& src = TextureVK::Cast(*source);
|
||||
const auto& dst = TextureVK::Cast(*destination);
|
||||
|
||||
const auto src_layout = vk::ImageLayout::eTransferSrcOptimal;
|
||||
const auto dst_layout = vk::ImageLayout::eTransferDstOptimal;
|
||||
LayoutTransition src_tran;
|
||||
src_tran.cmd_buffer = cmd_buffer;
|
||||
src_tran.new_layout = vk::ImageLayout::eTransferSrcOptimal;
|
||||
src_tran.src_access = vk::AccessFlagBits::eTransferWrite |
|
||||
vk::AccessFlagBits::eShaderWrite |
|
||||
vk::AccessFlagBits::eColorAttachmentWrite;
|
||||
src_tran.src_stage = vk::PipelineStageFlagBits::eTransfer |
|
||||
vk::PipelineStageFlagBits::eFragmentShader |
|
||||
vk::PipelineStageFlagBits::eColorAttachmentOutput;
|
||||
src_tran.dst_access = vk::AccessFlagBits::eTransferRead;
|
||||
src_tran.dst_stage = vk::PipelineStageFlagBits::eTransfer;
|
||||
|
||||
if (!src.SetLayout(src_layout, cmd_buffer) ||
|
||||
!dst.SetLayout(dst_layout, cmd_buffer)) {
|
||||
LayoutTransition dst_tran;
|
||||
dst_tran.cmd_buffer = cmd_buffer;
|
||||
dst_tran.new_layout = vk::ImageLayout::eTransferDstOptimal;
|
||||
dst_tran.src_access = {};
|
||||
dst_tran.src_stage = vk::PipelineStageFlagBits::eTopOfPipe;
|
||||
dst_tran.dst_access = vk::AccessFlagBits::eShaderRead;
|
||||
dst_tran.dst_stage = vk::PipelineStageFlagBits::eFragmentShader;
|
||||
|
||||
if (!src.SetLayout(src_tran) || !dst.SetLayout(dst_tran)) {
|
||||
VALIDATION_LOG << "Could not complete layout transitions.";
|
||||
return false;
|
||||
}
|
||||
@@ -54,11 +70,11 @@ bool BlitCopyTextureToTextureCommandVK::Encode(
|
||||
|
||||
// Issue the copy command now that the images are already in the right
|
||||
// layouts.
|
||||
cmd_buffer.copyImage(src.GetImage(), //
|
||||
src_layout, //
|
||||
dst.GetImage(), //
|
||||
dst_layout, //
|
||||
image_copy //
|
||||
cmd_buffer.copyImage(src.GetImage(), //
|
||||
src_tran.new_layout, //
|
||||
dst.GetImage(), //
|
||||
dst_tran.new_layout, //
|
||||
image_copy //
|
||||
);
|
||||
|
||||
return true;
|
||||
@@ -79,6 +95,20 @@ bool BlitCopyTextureToBufferCommandVK::Encode(CommandEncoderVK& encoder) const {
|
||||
|
||||
// cast source and destination to TextureVK
|
||||
const auto& src = TextureVK::Cast(*source);
|
||||
|
||||
LayoutTransition transition;
|
||||
transition.cmd_buffer = cmd_buffer;
|
||||
transition.new_layout = vk::ImageLayout::eTransferSrcOptimal;
|
||||
transition.src_access = vk::AccessFlagBits::eShaderWrite |
|
||||
vk::AccessFlagBits::eTransferWrite |
|
||||
vk::AccessFlagBits::eColorAttachmentWrite;
|
||||
transition.src_stage = vk::PipelineStageFlagBits::eFragmentShader |
|
||||
vk::PipelineStageFlagBits::eTransfer |
|
||||
vk::PipelineStageFlagBits::eColorAttachmentOutput;
|
||||
transition.dst_access = vk::AccessFlagBits::eShaderRead;
|
||||
transition.dst_stage = vk::PipelineStageFlagBits::eVertexShader |
|
||||
vk::PipelineStageFlagBits::eFragmentShader;
|
||||
|
||||
const auto& dst = DeviceBufferVK::Cast(*destination);
|
||||
|
||||
vk::BufferImageCopy image_copy;
|
||||
@@ -92,15 +122,15 @@ bool BlitCopyTextureToBufferCommandVK::Encode(CommandEncoderVK& encoder) const {
|
||||
image_copy.setImageExtent(
|
||||
vk::Extent3D(source_region.size.width, source_region.size.height, 1));
|
||||
|
||||
if (!src.SetLayout(vk::ImageLayout::eTransferSrcOptimal, cmd_buffer)) {
|
||||
if (!src.SetLayout(transition)) {
|
||||
VALIDATION_LOG << "Could not encode layout transition.";
|
||||
return false;
|
||||
}
|
||||
|
||||
cmd_buffer.copyImageToBuffer(src.GetImage(), //
|
||||
vk::ImageLayout::eTransferSrcOptimal, //
|
||||
dst.GetVKBufferHandle(), //
|
||||
image_copy //
|
||||
cmd_buffer.copyImageToBuffer(src.GetImage(), //
|
||||
transition.new_layout, //
|
||||
dst.GetBuffer(), //
|
||||
image_copy //
|
||||
);
|
||||
|
||||
return true;
|
||||
@@ -204,10 +234,12 @@ bool BlitGenerateMipmapCommandVK::Encode(CommandEncoderVK& encoder) const {
|
||||
// offsets[0] is origin.
|
||||
blit.srcOffsets[1].x = size.width;
|
||||
blit.srcOffsets[1].y = size.height;
|
||||
blit.srcOffsets[1].z = 1u;
|
||||
|
||||
// offsets[0] is origin.
|
||||
blit.dstOffsets[1].x = size.width >> mip_level;
|
||||
blit.dstOffsets[1].y = size.height >> mip_level;
|
||||
blit.dstOffsets[1].x = std::max<int32_t>(size.width >> mip_level, 1u);
|
||||
blit.dstOffsets[1].y = std::max<int32_t>(size.height >> mip_level, 1u);
|
||||
blit.dstOffsets[1].z = 1u;
|
||||
|
||||
cmd.blitImage(image, // src image
|
||||
vk::ImageLayout::eTransferSrcOptimal, // src layout
|
||||
@@ -222,27 +254,27 @@ bool BlitGenerateMipmapCommandVK::Encode(CommandEncoderVK& encoder) const {
|
||||
// Transition all mip levels to shader read. The base mip level has a
|
||||
// different "old" layout than the rest now.
|
||||
InsertImageMemoryBarrier(
|
||||
cmd, // command buffer
|
||||
image, // image
|
||||
vk::AccessFlagBits::eTransferRead, // src access mask
|
||||
vk::AccessFlagBits::eShaderRead, // dst access mask
|
||||
vk::ImageLayout::eTransferSrcOptimal, // old layout
|
||||
vk::ImageLayout::eShaderReadOnlyOptimal, // new layout
|
||||
vk::PipelineStageFlagBits::eTransfer, // src stage
|
||||
vk::PipelineStageFlagBits::eAllGraphics, // dst stage
|
||||
0u // mip level
|
||||
cmd, // command buffer
|
||||
image, // image
|
||||
vk::AccessFlagBits::eTransferWrite, // src access mask
|
||||
vk::AccessFlagBits::eShaderRead, // dst access mask
|
||||
vk::ImageLayout::eTransferSrcOptimal, // old layout
|
||||
vk::ImageLayout::eShaderReadOnlyOptimal, // new layout
|
||||
vk::PipelineStageFlagBits::eTransfer, // src stage
|
||||
vk::PipelineStageFlagBits::eFragmentShader, // dst stage
|
||||
0u // mip level
|
||||
);
|
||||
InsertImageMemoryBarrier(
|
||||
cmd, // command buffer
|
||||
image, // image
|
||||
vk::AccessFlagBits::eTransferRead, // src access mask
|
||||
vk::AccessFlagBits::eShaderRead, // dst access mask
|
||||
vk::ImageLayout::eTransferDstOptimal, // old layout
|
||||
vk::ImageLayout::eShaderReadOnlyOptimal, // new layout
|
||||
vk::PipelineStageFlagBits::eTransfer, // src stage
|
||||
vk::PipelineStageFlagBits::eAllGraphics, // dst stage
|
||||
1u, // mip level
|
||||
mip_count - 1 // mip level count
|
||||
cmd, // command buffer
|
||||
image, // image
|
||||
vk::AccessFlagBits::eTransferWrite, // src access mask
|
||||
vk::AccessFlagBits::eShaderRead, // dst access mask
|
||||
vk::ImageLayout::eTransferDstOptimal, // old layout
|
||||
vk::ImageLayout::eShaderReadOnlyOptimal, // new layout
|
||||
vk::PipelineStageFlagBits::eTransfer, // src stage
|
||||
vk::PipelineStageFlagBits::eFragmentShader, // dst stage
|
||||
1u, // mip level
|
||||
mip_count - 1 // mip level count
|
||||
);
|
||||
|
||||
// We modified the layouts of this image from underneath it. Tell it its new
|
||||
|
||||
@@ -4,39 +4,337 @@
|
||||
|
||||
#include "impeller/renderer/backend/vulkan/capabilities_vk.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "impeller/base/validation.h"
|
||||
#include "impeller/renderer/backend/vulkan/vk.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
CapabilitiesVK::CapabilitiesVK() {
|
||||
for (const auto& ext : vk::enumerateInstanceExtensionProperties().value) {
|
||||
extensions_.insert(ext.extensionName);
|
||||
static constexpr const char* kInstanceLayer = "ImpellerInstance";
|
||||
|
||||
CapabilitiesVK::CapabilitiesVK(bool enable_validations)
|
||||
: enable_validations_(enable_validations) {
|
||||
auto extensions = vk::enumerateInstanceExtensionProperties();
|
||||
auto layers = vk::enumerateInstanceLayerProperties();
|
||||
|
||||
if (extensions.result != vk::Result::eSuccess ||
|
||||
layers.result != vk::Result::eSuccess) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& layer : vk::enumerateInstanceLayerProperties().value) {
|
||||
layers_.insert(layer.layerName);
|
||||
for (const auto& ext : extensions.value) {
|
||||
exts_[kInstanceLayer].insert(ext.extensionName);
|
||||
}
|
||||
|
||||
for (const auto& layer : layers.value) {
|
||||
const std::string layer_name = layer.layerName;
|
||||
auto layer_exts = vk::enumerateInstanceExtensionProperties(layer_name);
|
||||
if (layer_exts.result != vk::Result::eSuccess) {
|
||||
return;
|
||||
}
|
||||
for (const auto& layer_ext : layer_exts.value) {
|
||||
exts_[layer_name].insert(layer_ext.extensionName);
|
||||
}
|
||||
}
|
||||
|
||||
is_valid_ = true;
|
||||
}
|
||||
|
||||
CapabilitiesVK::~CapabilitiesVK() = default;
|
||||
|
||||
bool CapabilitiesVK::HasExtension(const std::string& extension) const {
|
||||
return extensions_.count(extension) == 1u;
|
||||
bool CapabilitiesVK::IsValid() const {
|
||||
return is_valid_;
|
||||
}
|
||||
|
||||
bool CapabilitiesVK::AreValidationsEnabled() const {
|
||||
return enable_validations_;
|
||||
}
|
||||
|
||||
std::optional<std::vector<std::string>> CapabilitiesVK::GetRequiredLayers()
|
||||
const {
|
||||
std::vector<std::string> required;
|
||||
|
||||
if (enable_validations_) {
|
||||
if (!HasLayer("VK_LAYER_KHRONOS_validation")) {
|
||||
VALIDATION_LOG
|
||||
<< "Requested validations but the validation layer was not found.";
|
||||
return std::nullopt;
|
||||
}
|
||||
required.push_back("VK_LAYER_KHRONOS_validation");
|
||||
}
|
||||
|
||||
return required;
|
||||
}
|
||||
|
||||
std::optional<std::vector<std::string>>
|
||||
CapabilitiesVK::GetRequiredInstanceExtensions() const {
|
||||
std::vector<std::string> required;
|
||||
|
||||
if (!HasExtension("VK_KHR_surface")) {
|
||||
// Swapchain support is required and this is a dependency of
|
||||
// VK_KHR_swapchain.
|
||||
VALIDATION_LOG << "Could not find the surface extension.";
|
||||
return std::nullopt;
|
||||
}
|
||||
required.push_back("VK_KHR_surface");
|
||||
|
||||
auto has_wsi = false;
|
||||
if (HasExtension("VK_MVK_macos_surface")) {
|
||||
required.push_back("VK_MVK_macos_surface");
|
||||
has_wsi = true;
|
||||
}
|
||||
|
||||
if (HasExtension("VK_EXT_metal_surface")) {
|
||||
required.push_back("VK_EXT_metal_surface");
|
||||
has_wsi = true;
|
||||
}
|
||||
|
||||
if (HasExtension("VK_KHR_portability_enumeration")) {
|
||||
required.push_back("VK_KHR_portability_enumeration");
|
||||
has_wsi = true;
|
||||
}
|
||||
|
||||
if (HasExtension("VK_KHR_win32_surface")) {
|
||||
required.push_back("VK_KHR_win32_surface");
|
||||
has_wsi = true;
|
||||
}
|
||||
|
||||
if (HasExtension("VK_KHR_android_surface")) {
|
||||
required.push_back("VK_KHR_android_surface");
|
||||
has_wsi = true;
|
||||
}
|
||||
|
||||
if (HasExtension("VK_KHR_xcb_surface")) {
|
||||
required.push_back("VK_KHR_xcb_surface");
|
||||
has_wsi = true;
|
||||
}
|
||||
|
||||
if (HasExtension("VK_KHR_xlib_surface")) {
|
||||
required.push_back("VK_KHR_xlib_surface");
|
||||
has_wsi = true;
|
||||
}
|
||||
|
||||
if (HasExtension("VK_KHR_wayland_surface")) {
|
||||
required.push_back("VK_KHR_wayland_surface");
|
||||
has_wsi = true;
|
||||
}
|
||||
|
||||
if (!has_wsi) {
|
||||
// Don't really care which WSI extension there is as long there is at least
|
||||
// one.
|
||||
VALIDATION_LOG << "Could not find a WSI extension.";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (enable_validations_) {
|
||||
if (!HasExtension("VK_EXT_debug_utils")) {
|
||||
VALIDATION_LOG << "Requested validations but could not find the "
|
||||
"VK_EXT_debug_utils extension.";
|
||||
return std::nullopt;
|
||||
}
|
||||
required.push_back("VK_EXT_debug_utils");
|
||||
|
||||
if (!HasExtension("VK_EXT_validation_features")) {
|
||||
VALIDATION_LOG << "Requested validations but could not find the "
|
||||
"VK_EXT_validation_features extension.";
|
||||
return std::nullopt;
|
||||
}
|
||||
required.push_back("VK_EXT_validation_features");
|
||||
}
|
||||
|
||||
return required;
|
||||
}
|
||||
|
||||
std::optional<std::vector<std::string>>
|
||||
CapabilitiesVK::GetRequiredDeviceExtensions(
|
||||
const vk::PhysicalDevice& physical_device) const {
|
||||
auto device_extensions = physical_device.enumerateDeviceExtensionProperties();
|
||||
if (device_extensions.result != vk::Result::eSuccess) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::set<std::string> exts;
|
||||
for (const auto& device_extension : device_extensions.value) {
|
||||
exts.insert(device_extension.extensionName);
|
||||
}
|
||||
|
||||
std::vector<std::string> required;
|
||||
|
||||
if (exts.find("VK_KHR_swapchain") == exts.end()) {
|
||||
VALIDATION_LOG << "Device does not support the swapchain extension.";
|
||||
return std::nullopt;
|
||||
}
|
||||
required.push_back("VK_KHR_swapchain");
|
||||
|
||||
// Required for non-conformant implementations like MoltenVK.
|
||||
if (exts.find("VK_KHR_portability_subset") != exts.end()) {
|
||||
required.push_back("VK_KHR_portability_subset");
|
||||
}
|
||||
return required;
|
||||
}
|
||||
|
||||
static bool HasSuitableColorFormat(const vk::PhysicalDevice& device,
|
||||
vk::Format format) {
|
||||
const auto props = device.getFormatProperties(format);
|
||||
// This needs to be more comprehensive.
|
||||
return !!(props.optimalTilingFeatures &
|
||||
vk::FormatFeatureFlagBits::eColorAttachment);
|
||||
}
|
||||
|
||||
static bool HasSuitableDepthStencilFormat(const vk::PhysicalDevice& device,
|
||||
vk::Format format) {
|
||||
const auto props = device.getFormatProperties(format);
|
||||
return !!(props.optimalTilingFeatures &
|
||||
vk::FormatFeatureFlagBits::eDepthStencilAttachment);
|
||||
}
|
||||
|
||||
static bool PhysicalDeviceSupportsRequiredFormats(
|
||||
const vk::PhysicalDevice& device) {
|
||||
const auto has_color_format =
|
||||
HasSuitableColorFormat(device, vk::Format::eB8G8R8A8Unorm);
|
||||
const auto has_depth_stencil_format =
|
||||
HasSuitableDepthStencilFormat(device, vk::Format::eS8Uint) ||
|
||||
HasSuitableDepthStencilFormat(device, vk::Format::eD24UnormS8Uint);
|
||||
return has_color_format && has_depth_stencil_format;
|
||||
}
|
||||
|
||||
static bool HasRequiredProperties(const vk::PhysicalDevice& physical_device) {
|
||||
auto properties = physical_device.getProperties();
|
||||
if (!(properties.limits.framebufferColorSampleCounts &
|
||||
(vk::SampleCountFlagBits::e1 | vk::SampleCountFlagBits::e4))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HasRequiredQueues(const vk::PhysicalDevice& physical_device) {
|
||||
auto queue_flags = vk::QueueFlags{};
|
||||
for (const auto& queue : physical_device.getQueueFamilyProperties()) {
|
||||
if (queue.queueCount == 0) {
|
||||
continue;
|
||||
}
|
||||
queue_flags |= queue.queueFlags;
|
||||
}
|
||||
return static_cast<VkQueueFlags>(queue_flags &
|
||||
(vk::QueueFlagBits::eGraphics |
|
||||
vk::QueueFlagBits::eCompute |
|
||||
vk::QueueFlagBits::eTransfer));
|
||||
}
|
||||
|
||||
std::optional<vk::PhysicalDeviceFeatures>
|
||||
CapabilitiesVK::GetRequiredDeviceFeatures(
|
||||
const vk::PhysicalDevice& device) const {
|
||||
if (!PhysicalDeviceSupportsRequiredFormats(device)) {
|
||||
VALIDATION_LOG << "Device doesn't support the required formats.";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!HasRequiredProperties(device)) {
|
||||
VALIDATION_LOG << "Device doesn't support the required properties.";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!HasRequiredQueues(device)) {
|
||||
VALIDATION_LOG << "Device doesn't support the required queues.";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!GetRequiredDeviceExtensions(device).has_value()) {
|
||||
VALIDATION_LOG << "Device doesn't support the required queues.";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const auto device_features = device.getFeatures();
|
||||
|
||||
vk::PhysicalDeviceFeatures required;
|
||||
|
||||
// We require this for enabling wireframes in the playground. But its not
|
||||
// necessarily a big deal if we don't have this feature.
|
||||
required.fillModeNonSolid = device_features.fillModeNonSolid;
|
||||
|
||||
return required;
|
||||
}
|
||||
|
||||
bool CapabilitiesVK::HasLayer(const std::string& layer) const {
|
||||
return layers_.count(layer) == 1u;
|
||||
}
|
||||
|
||||
bool CapabilitiesVK::HasLayerExtension(const std::string& layer,
|
||||
const std::string& extension) {
|
||||
for (const auto& ext :
|
||||
vk::enumerateInstanceExtensionProperties(layer).value) {
|
||||
if (std::string{ext.extensionName} == extension) {
|
||||
for (const auto& [found_layer, exts] : exts_) {
|
||||
if (found_layer == layer) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CapabilitiesVK::HasExtension(const std::string& ext) const {
|
||||
for (const auto& [layer, exts] : exts_) {
|
||||
if (exts.find(ext) != exts.end()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CapabilitiesVK::SetDevice(const vk::PhysicalDevice& device) {
|
||||
if (HasSuitableColorFormat(device, vk::Format::eB8G8R8A8Unorm)) {
|
||||
color_format_ = PixelFormat::kB8G8R8A8UNormInt;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (HasSuitableDepthStencilFormat(device, vk::Format::eS8Uint)) {
|
||||
depth_stencil_format_ = PixelFormat::kS8UInt;
|
||||
} else if (HasSuitableDepthStencilFormat(device,
|
||||
vk::Format::eD24UnormS8Uint)) {
|
||||
depth_stencil_format_ = PixelFormat::kD32FloatS8UInt;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// |Capabilities|
|
||||
bool CapabilitiesVK::HasThreadingRestrictions() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
// |Capabilities|
|
||||
bool CapabilitiesVK::SupportsOffscreenMSAA() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
// |Capabilities|
|
||||
bool CapabilitiesVK::SupportsSSBO() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
// |Capabilities|
|
||||
bool CapabilitiesVK::SupportsTextureToTextureBlits() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
// |Capabilities|
|
||||
bool CapabilitiesVK::SupportsFramebufferFetch() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
// |Capabilities|
|
||||
bool CapabilitiesVK::SupportsCompute() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
// |Capabilities|
|
||||
bool CapabilitiesVK::SupportsComputeSubgroups() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
// |Capabilities|
|
||||
PixelFormat CapabilitiesVK::GetDefaultColorFormat() const {
|
||||
return color_format_;
|
||||
}
|
||||
|
||||
// |Capabilities|
|
||||
PixelFormat CapabilitiesVK::GetDefaultStencilFormat() const {
|
||||
return depth_stencil_format_;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@@ -4,29 +4,81 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/renderer/backend/vulkan/vk.h"
|
||||
#include "impeller/renderer/capabilities.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
class CapabilitiesVK {
|
||||
class ContextVK;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @brief The Vulkan layers and extensions wrangler.
|
||||
///
|
||||
class CapabilitiesVK final : public Capabilities {
|
||||
public:
|
||||
CapabilitiesVK();
|
||||
CapabilitiesVK(bool enable_validations = false);
|
||||
|
||||
~CapabilitiesVK();
|
||||
|
||||
bool HasExtension(const std::string& extension) const;
|
||||
bool IsValid() const;
|
||||
|
||||
bool HasLayer(const std::string& layer) const;
|
||||
bool AreValidationsEnabled() const;
|
||||
|
||||
bool HasLayerExtension(const std::string& layer,
|
||||
const std::string& extension);
|
||||
std::optional<std::vector<std::string>> GetRequiredLayers() const;
|
||||
|
||||
std::optional<std::vector<std::string>> GetRequiredInstanceExtensions() const;
|
||||
|
||||
std::optional<std::vector<std::string>> GetRequiredDeviceExtensions(
|
||||
const vk::PhysicalDevice& physical_device) const;
|
||||
|
||||
std::optional<vk::PhysicalDeviceFeatures> GetRequiredDeviceFeatures(
|
||||
const vk::PhysicalDevice& physical_device) const;
|
||||
|
||||
[[nodiscard]] bool SetDevice(const vk::PhysicalDevice& physical_device);
|
||||
|
||||
// |Capabilities|
|
||||
bool HasThreadingRestrictions() const override;
|
||||
|
||||
// |Capabilities|
|
||||
bool SupportsOffscreenMSAA() const override;
|
||||
|
||||
// |Capabilities|
|
||||
bool SupportsSSBO() const override;
|
||||
|
||||
// |Capabilities|
|
||||
bool SupportsTextureToTextureBlits() const override;
|
||||
|
||||
// |Capabilities|
|
||||
bool SupportsFramebufferFetch() const override;
|
||||
|
||||
// |Capabilities|
|
||||
bool SupportsCompute() const override;
|
||||
|
||||
// |Capabilities|
|
||||
bool SupportsComputeSubgroups() const override;
|
||||
|
||||
// |Capabilities|
|
||||
PixelFormat GetDefaultColorFormat() const override;
|
||||
|
||||
// |Capabilities|
|
||||
PixelFormat GetDefaultStencilFormat() const override;
|
||||
|
||||
private:
|
||||
std::set<std::string> extensions_;
|
||||
std::set<std::string> layers_;
|
||||
const bool enable_validations_;
|
||||
std::map<std::string, std::set<std::string>> exts_;
|
||||
PixelFormat color_format_ = PixelFormat::kUnknown;
|
||||
PixelFormat depth_stencil_format_ = PixelFormat::kUnknown;
|
||||
bool is_valid_ = false;
|
||||
|
||||
bool HasExtension(const std::string& ext) const;
|
||||
|
||||
bool HasLayer(const std::string& layer) const;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(CapabilitiesVK);
|
||||
};
|
||||
|
||||
@@ -5,31 +5,91 @@
|
||||
#include "impeller/renderer/backend/vulkan/command_encoder_vk.h"
|
||||
|
||||
#include "flutter/fml/closure.h"
|
||||
#include "flutter/fml/trace_event.h"
|
||||
#include "impeller/renderer/backend/vulkan/context_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/fence_waiter_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/texture_vk.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
class TrackedObjectsVK {
|
||||
public:
|
||||
explicit TrackedObjectsVK(const vk::Device& device,
|
||||
const std::shared_ptr<CommandPoolVK>& pool)
|
||||
: desc_pool_(device) {
|
||||
if (!pool) {
|
||||
return;
|
||||
}
|
||||
auto buffer = pool->CreateGraphicsCommandBuffer();
|
||||
if (!buffer) {
|
||||
return;
|
||||
}
|
||||
pool_ = pool;
|
||||
buffer_ = std::move(buffer);
|
||||
is_valid_ = true;
|
||||
}
|
||||
|
||||
~TrackedObjectsVK() {
|
||||
if (!buffer_) {
|
||||
return;
|
||||
}
|
||||
auto pool = pool_.lock();
|
||||
if (!pool) {
|
||||
VALIDATION_LOG
|
||||
<< "Command pool died before a command buffer could be recycled.";
|
||||
return;
|
||||
}
|
||||
pool->CollectGraphicsCommandBuffer(std::move(buffer_));
|
||||
}
|
||||
|
||||
bool IsValid() const { return is_valid_; }
|
||||
|
||||
void Track(std::shared_ptr<SharedObjectVK> object) {
|
||||
tracked_objects_.insert(std::move(object));
|
||||
}
|
||||
|
||||
void Track(std::shared_ptr<const DeviceBuffer> buffer) {
|
||||
tracked_buffers_.insert(std::move(buffer));
|
||||
}
|
||||
|
||||
void Track(std::shared_ptr<const TextureSourceVK> texture) {
|
||||
tracked_textures_.insert(std::move(texture));
|
||||
}
|
||||
|
||||
vk::CommandBuffer GetCommandBuffer() const { return *buffer_; }
|
||||
|
||||
DescriptorPoolVK& GetDescriptorPool() { return desc_pool_; }
|
||||
|
||||
private:
|
||||
DescriptorPoolVK desc_pool_;
|
||||
std::weak_ptr<CommandPoolVK> pool_;
|
||||
vk::UniqueCommandBuffer buffer_;
|
||||
std::set<std::shared_ptr<SharedObjectVK>> tracked_objects_;
|
||||
std::set<std::shared_ptr<const DeviceBuffer>> tracked_buffers_;
|
||||
std::set<std::shared_ptr<const TextureSourceVK>> tracked_textures_;
|
||||
bool is_valid_ = false;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(TrackedObjectsVK);
|
||||
};
|
||||
|
||||
CommandEncoderVK::CommandEncoderVK(vk::Device device,
|
||||
vk::Queue queue,
|
||||
vk::CommandPool pool) {
|
||||
vk::CommandBufferAllocateInfo alloc_info;
|
||||
alloc_info.commandPool = pool;
|
||||
alloc_info.commandBufferCount = 1u;
|
||||
alloc_info.level = vk::CommandBufferLevel::ePrimary;
|
||||
auto [result, buffers] = device.allocateCommandBuffersUnique(alloc_info);
|
||||
if (result != vk::Result::eSuccess) {
|
||||
VALIDATION_LOG << "Could not create command buffer.";
|
||||
const std::shared_ptr<CommandPoolVK>& pool,
|
||||
std::shared_ptr<FenceWaiterVK> fence_waiter)
|
||||
: fence_waiter_(std::move(fence_waiter)),
|
||||
tracked_objects_(std::make_shared<TrackedObjectsVK>(device, pool)) {
|
||||
if (!fence_waiter_ || !tracked_objects_->IsValid()) {
|
||||
return;
|
||||
}
|
||||
vk::CommandBufferBeginInfo begin_info;
|
||||
begin_info.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit;
|
||||
if (buffers[0]->begin(begin_info) != vk::Result::eSuccess) {
|
||||
if (tracked_objects_->GetCommandBuffer().begin(begin_info) !=
|
||||
vk::Result::eSuccess) {
|
||||
VALIDATION_LOG << "Could not begin command buffer.";
|
||||
return;
|
||||
}
|
||||
device_ = device;
|
||||
queue_ = queue;
|
||||
command_buffer_ = std::move(buffers[0]);
|
||||
is_valid_ = true;
|
||||
}
|
||||
|
||||
@@ -47,39 +107,40 @@ bool CommandEncoderVK::Submit() {
|
||||
// Success or failure, you only get to submit once.
|
||||
fml::ScopedCleanupClosure reset([&]() { Reset(); });
|
||||
|
||||
if (command_buffer_->end() != vk::Result::eSuccess) {
|
||||
InsertDebugMarker("QueueSubmit");
|
||||
|
||||
auto command_buffer = GetCommandBuffer();
|
||||
|
||||
if (command_buffer.end() != vk::Result::eSuccess) {
|
||||
return false;
|
||||
}
|
||||
auto [fence_result, fence] = device_.createFenceUnique({});
|
||||
if (fence_result != vk::Result::eSuccess) {
|
||||
return false;
|
||||
}
|
||||
|
||||
vk::SubmitInfo submit_info;
|
||||
submit_info.setCommandBuffers(*command_buffer_);
|
||||
std::vector<vk::CommandBuffer> buffers = {command_buffer};
|
||||
submit_info.setCommandBuffers(buffers);
|
||||
if (queue_.submit(submit_info, *fence) != vk::Result::eSuccess) {
|
||||
return false;
|
||||
}
|
||||
if (device_.waitForFences(
|
||||
*fence, // fences
|
||||
true, // wait all
|
||||
std::numeric_limits<uint64_t>::max() // timeout (ns)
|
||||
) != vk::Result::eSuccess) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return fence_waiter_->AddFence(
|
||||
std::move(fence), [tracked_objects = std::move(tracked_objects_)] {
|
||||
// Nothing to do, we just drop the tracked objects on the floor.
|
||||
});
|
||||
}
|
||||
|
||||
const vk::CommandBuffer& CommandEncoderVK::GetCommandBuffer() const {
|
||||
return *command_buffer_;
|
||||
vk::CommandBuffer CommandEncoderVK::GetCommandBuffer() const {
|
||||
if (tracked_objects_) {
|
||||
return tracked_objects_->GetCommandBuffer();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void CommandEncoderVK::Reset() {
|
||||
command_buffer_.reset();
|
||||
|
||||
tracked_objects_.clear();
|
||||
tracked_buffers_.clear();
|
||||
tracked_textures_.clear();
|
||||
tracked_objects_.reset();
|
||||
|
||||
queue_ = nullptr;
|
||||
device_ = nullptr;
|
||||
@@ -87,34 +148,82 @@ void CommandEncoderVK::Reset() {
|
||||
}
|
||||
|
||||
bool CommandEncoderVK::Track(std::shared_ptr<SharedObjectVK> object) {
|
||||
tracked_objects_.push_back(std::move(object));
|
||||
if (!IsValid()) {
|
||||
return false;
|
||||
}
|
||||
tracked_objects_->Track(std::move(object));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CommandEncoderVK::Track(std::shared_ptr<const DeviceBuffer> buffer) {
|
||||
tracked_buffers_.emplace_back(std::move(buffer));
|
||||
if (!IsValid()) {
|
||||
return false;
|
||||
}
|
||||
tracked_objects_->Track(std::move(buffer));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CommandEncoderVK::Track(std::shared_ptr<const Texture> texture) {
|
||||
tracked_textures_.emplace_back(std::move(texture));
|
||||
bool CommandEncoderVK::Track(std::shared_ptr<const TextureSourceVK> texture) {
|
||||
if (!IsValid()) {
|
||||
return false;
|
||||
}
|
||||
tracked_objects_->Track(std::move(texture));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CommandEncoderVK::Track(const std::shared_ptr<const Texture>& texture) {
|
||||
if (!texture) {
|
||||
return false;
|
||||
}
|
||||
return Track(TextureVK::Cast(*texture).GetTextureSource());
|
||||
}
|
||||
|
||||
std::optional<vk::DescriptorSet> CommandEncoderVK::AllocateDescriptorSet(
|
||||
const vk::DescriptorSetLayout& layout) {
|
||||
if (!IsValid()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return tracked_objects_->GetDescriptorPool().AllocateDescriptorSet(layout);
|
||||
}
|
||||
|
||||
void CommandEncoderVK::PushDebugGroup(const char* label) const {
|
||||
if (!vk::HasValidationLayers() || !command_buffer_) {
|
||||
if (!HasValidationLayers()) {
|
||||
return;
|
||||
}
|
||||
vk::DebugUtilsLabelEXT label_info;
|
||||
label_info.pLabelName = label;
|
||||
command_buffer_->beginDebugUtilsLabelEXT(label_info);
|
||||
if (auto command_buffer = GetCommandBuffer()) {
|
||||
command_buffer.beginDebugUtilsLabelEXT(label_info);
|
||||
}
|
||||
if (queue_) {
|
||||
queue_.beginDebugUtilsLabelEXT(label_info);
|
||||
}
|
||||
}
|
||||
|
||||
void CommandEncoderVK::PopDebugGroup() const {
|
||||
if (!vk::HasValidationLayers() || !command_buffer_) {
|
||||
if (!HasValidationLayers()) {
|
||||
return;
|
||||
}
|
||||
command_buffer_->endDebugUtilsLabelEXT();
|
||||
if (auto command_buffer = GetCommandBuffer()) {
|
||||
command_buffer.endDebugUtilsLabelEXT();
|
||||
}
|
||||
if (queue_) {
|
||||
queue_.endDebugUtilsLabelEXT();
|
||||
}
|
||||
}
|
||||
|
||||
void CommandEncoderVK::InsertDebugMarker(const char* label) const {
|
||||
if (!HasValidationLayers()) {
|
||||
return;
|
||||
}
|
||||
vk::DebugUtilsLabelEXT label_info;
|
||||
label_info.pLabelName = label;
|
||||
if (auto command_buffer = GetCommandBuffer()) {
|
||||
command_buffer.insertDebugUtilsLabelEXT(label_info);
|
||||
}
|
||||
if (queue_) {
|
||||
queue_.insertDebugUtilsLabelEXT(label_info);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@@ -4,9 +4,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/renderer/backend/vulkan/command_pool_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/descriptor_pool_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/shared_object_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/vk.h"
|
||||
|
||||
@@ -15,6 +18,9 @@ namespace impeller {
|
||||
class ContextVK;
|
||||
class DeviceBuffer;
|
||||
class Texture;
|
||||
class TextureSourceVK;
|
||||
class TrackedObjectsVK;
|
||||
class FenceWaiterVK;
|
||||
|
||||
class CommandEncoderVK {
|
||||
public:
|
||||
@@ -28,26 +34,35 @@ class CommandEncoderVK {
|
||||
|
||||
bool Track(std::shared_ptr<const DeviceBuffer> buffer);
|
||||
|
||||
bool Track(std::shared_ptr<const Texture> texture);
|
||||
bool Track(const std::shared_ptr<const Texture>& texture);
|
||||
|
||||
const vk::CommandBuffer& GetCommandBuffer() const;
|
||||
bool Track(std::shared_ptr<const TextureSourceVK> texture);
|
||||
|
||||
vk::CommandBuffer GetCommandBuffer() const;
|
||||
|
||||
void PushDebugGroup(const char* label) const;
|
||||
|
||||
void PopDebugGroup() const;
|
||||
|
||||
void InsertDebugMarker(const char* label) const;
|
||||
|
||||
std::optional<vk::DescriptorSet> AllocateDescriptorSet(
|
||||
const vk::DescriptorSetLayout& layout);
|
||||
|
||||
private:
|
||||
friend class ContextVK;
|
||||
|
||||
vk::Device device_ = {};
|
||||
vk::Queue queue_ = {};
|
||||
vk::UniqueCommandBuffer command_buffer_;
|
||||
std::vector<std::shared_ptr<SharedObjectVK>> tracked_objects_;
|
||||
std::vector<std::shared_ptr<const DeviceBuffer>> tracked_buffers_;
|
||||
std::vector<std::shared_ptr<const Texture>> tracked_textures_;
|
||||
|
||||
std::shared_ptr<FenceWaiterVK> fence_waiter_;
|
||||
std::shared_ptr<TrackedObjectsVK> tracked_objects_;
|
||||
bool is_valid_ = false;
|
||||
|
||||
CommandEncoderVK(vk::Device device, vk::Queue queue, vk::CommandPool pool);
|
||||
CommandEncoderVK(vk::Device device,
|
||||
vk::Queue queue,
|
||||
const std::shared_ptr<CommandPoolVK>& pool,
|
||||
std::shared_ptr<FenceWaiterVK> fence_waiter);
|
||||
|
||||
void Reset();
|
||||
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "impeller/renderer/backend/vulkan/command_pool_vk.h"
|
||||
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "flutter/fml/thread_local.h"
|
||||
#include "impeller/base/thread.h"
|
||||
#include "impeller/renderer/backend/vulkan/context_vk.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
using CommandPoolMap =
|
||||
std::map<const ContextVK*, std::shared_ptr<CommandPoolVK>>;
|
||||
|
||||
FML_THREAD_LOCAL fml::ThreadLocalUniquePtr<CommandPoolMap> tls_command_pool;
|
||||
|
||||
static Mutex g_all_pools_mutex;
|
||||
static std::unordered_map<const ContextVK*,
|
||||
std::vector<std::weak_ptr<CommandPoolVK>>>
|
||||
g_all_pools IPLR_GUARDED_BY(g_all_pools_mutex);
|
||||
|
||||
std::shared_ptr<CommandPoolVK> CommandPoolVK::GetThreadLocal(
|
||||
const ContextVK* context) {
|
||||
if (!context) {
|
||||
return nullptr;
|
||||
}
|
||||
if (tls_command_pool.get() == nullptr) {
|
||||
tls_command_pool.reset(new CommandPoolMap());
|
||||
}
|
||||
CommandPoolMap& pool_map = *tls_command_pool.get();
|
||||
auto found = pool_map.find(context);
|
||||
if (found != pool_map.end() && found->second->IsValid()) {
|
||||
return found->second;
|
||||
}
|
||||
auto pool = std::shared_ptr<CommandPoolVK>(new CommandPoolVK(context));
|
||||
if (!pool->IsValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
pool_map[context] = pool;
|
||||
{
|
||||
Lock pool_lock(g_all_pools_mutex);
|
||||
g_all_pools[context].push_back(pool);
|
||||
}
|
||||
return pool;
|
||||
}
|
||||
|
||||
void CommandPoolVK::ClearAllPools(const ContextVK* context) {
|
||||
Lock pool_lock(g_all_pools_mutex);
|
||||
if (auto found = g_all_pools.find(context); found != g_all_pools.end()) {
|
||||
for (auto& weak_pool : found->second) {
|
||||
auto pool = weak_pool.lock();
|
||||
if (!pool) {
|
||||
// The pool has already died because the thread died.
|
||||
continue;
|
||||
}
|
||||
// The pool is reset but its reference in the TLS map remains till the
|
||||
// thread dies.
|
||||
pool->Reset();
|
||||
}
|
||||
g_all_pools.erase(found);
|
||||
}
|
||||
}
|
||||
|
||||
CommandPoolVK::CommandPoolVK(const ContextVK* context)
|
||||
: owner_id_(std::this_thread::get_id()) {
|
||||
vk::CommandPoolCreateInfo pool_info;
|
||||
|
||||
pool_info.queueFamilyIndex = context->GetGraphicsQueueInfo().index;
|
||||
pool_info.flags = vk::CommandPoolCreateFlagBits::eTransient;
|
||||
auto pool = context->GetDevice().createCommandPoolUnique(pool_info);
|
||||
if (pool.result != vk::Result::eSuccess) {
|
||||
return;
|
||||
}
|
||||
|
||||
device_ = context->GetDevice();
|
||||
graphics_pool_ = std::move(pool.value);
|
||||
is_valid_ = true;
|
||||
}
|
||||
|
||||
CommandPoolVK::~CommandPoolVK() = default;
|
||||
|
||||
bool CommandPoolVK::IsValid() const {
|
||||
return is_valid_;
|
||||
}
|
||||
|
||||
void CommandPoolVK::Reset() {
|
||||
Lock lock(buffers_to_collect_mutex_);
|
||||
GarbageCollectBuffersIfAble();
|
||||
graphics_pool_.reset();
|
||||
is_valid_ = false;
|
||||
}
|
||||
|
||||
vk::CommandPool CommandPoolVK::GetGraphicsCommandPool() const {
|
||||
return graphics_pool_.get();
|
||||
}
|
||||
|
||||
vk::UniqueCommandBuffer CommandPoolVK::CreateGraphicsCommandBuffer() {
|
||||
if (std::this_thread::get_id() != owner_id_) {
|
||||
return {};
|
||||
}
|
||||
{
|
||||
Lock lock(buffers_to_collect_mutex_);
|
||||
GarbageCollectBuffersIfAble();
|
||||
}
|
||||
vk::CommandBufferAllocateInfo alloc_info;
|
||||
alloc_info.commandPool = graphics_pool_.get();
|
||||
alloc_info.commandBufferCount = 1u;
|
||||
alloc_info.level = vk::CommandBufferLevel::ePrimary;
|
||||
auto [result, buffers] = device_.allocateCommandBuffersUnique(alloc_info);
|
||||
if (result != vk::Result::eSuccess) {
|
||||
return {};
|
||||
}
|
||||
return std::move(buffers[0]);
|
||||
}
|
||||
|
||||
void CommandPoolVK::CollectGraphicsCommandBuffer(
|
||||
vk::UniqueCommandBuffer buffer) {
|
||||
Lock lock(buffers_to_collect_mutex_);
|
||||
buffers_to_collect_.insert(MakeSharedVK(std::move(buffer)));
|
||||
GarbageCollectBuffersIfAble();
|
||||
}
|
||||
|
||||
void CommandPoolVK::GarbageCollectBuffersIfAble() {
|
||||
if (std::this_thread::get_id() != owner_id_) {
|
||||
return;
|
||||
}
|
||||
buffers_to_collect_.clear();
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
@@ -0,0 +1,55 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <thread>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/base/thread.h"
|
||||
#include "impeller/renderer/backend/vulkan/shared_object_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/vk.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
class ContextVK;
|
||||
|
||||
class CommandPoolVK {
|
||||
public:
|
||||
static std::shared_ptr<CommandPoolVK> GetThreadLocal(
|
||||
const ContextVK* context);
|
||||
|
||||
static void ClearAllPools(const ContextVK* context);
|
||||
|
||||
~CommandPoolVK();
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
void Reset();
|
||||
|
||||
vk::CommandPool GetGraphicsCommandPool() const;
|
||||
|
||||
vk::UniqueCommandBuffer CreateGraphicsCommandBuffer();
|
||||
|
||||
void CollectGraphicsCommandBuffer(vk::UniqueCommandBuffer buffer);
|
||||
|
||||
private:
|
||||
const std::thread::id owner_id_;
|
||||
vk::Device device_ = {};
|
||||
vk::UniqueCommandPool graphics_pool_;
|
||||
Mutex buffers_to_collect_mutex_;
|
||||
std::set<SharedHandleVK<vk::CommandBuffer>> buffers_to_collect_
|
||||
IPLR_GUARDED_BY(buffers_to_collect_mutex_);
|
||||
bool is_valid_ = false;
|
||||
|
||||
explicit CommandPoolVK(const ContextVK* context);
|
||||
|
||||
void GarbageCollectBuffersIfAble() IPLR_REQUIRES(buffers_to_collect_mutex_);
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(CommandPoolVK);
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
@@ -20,156 +20,30 @@
|
||||
#include "impeller/renderer/backend/vulkan/capabilities_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/command_buffer_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/command_encoder_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/command_pool_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/debug_report_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/fence_waiter_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/formats_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/surface_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/vk.h"
|
||||
#include "impeller/renderer/device_capabilities.h"
|
||||
#include "impeller/renderer/capabilities.h"
|
||||
|
||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||
|
||||
namespace {
|
||||
|
||||
// TODO(csg): Mimic vulkan_debug_report.cc for prettier reports.
|
||||
VKAPI_ATTR VkBool32 VKAPI_CALL DebugUtilsMessengerCallback(
|
||||
VkDebugUtilsMessageSeverityFlagBitsEXT severity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT type,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||
void* pUserData) {
|
||||
// There isn't stable messageIdNumber for this validation failure.
|
||||
if (strstr(pCallbackData->pMessageIdName,
|
||||
"CoreValidation-Shader-OutputNotConsumed") != nullptr) {
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
if (pCallbackData->messageIdNumber == static_cast<int32_t>(0x82ae5050)) {
|
||||
// This is a real error but we can't fix it due to our headers being too
|
||||
// old. More more details see:
|
||||
// https://vulkan.lunarg.com/doc/view/1.3.224.1/mac/1.3-extensions/vkspec.html#VUID-VkImageViewCreateInfo-imageViewFormatSwizzle-04465
|
||||
// This validation error currently only trips on macOS due to the use of
|
||||
// texture swizzles.
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
const auto prefix = impeller::vk::to_string(
|
||||
impeller::vk::DebugUtilsMessageSeverityFlagBitsEXT(severity));
|
||||
// Just so that the log doesn't say FML_DCHECK(false).
|
||||
constexpr bool kVulkanValidationFailure = false;
|
||||
FML_DCHECK(kVulkanValidationFailure)
|
||||
<< prefix << "[" << pCallbackData->messageIdNumber << "]["
|
||||
<< pCallbackData->pMessageIdName << "] : " << pCallbackData->pMessage;
|
||||
|
||||
// The return value of this callback controls whether the Vulkan call that
|
||||
// caused the validation message will be aborted or not We return VK_TRUE as
|
||||
// we DO want Vulkan calls that cause a validation message to abort
|
||||
return VK_TRUE;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace impeller {
|
||||
|
||||
namespace vk {
|
||||
// TODO(csg): Fix this after caps are reworked.
|
||||
static bool gHasValidationLayers = false;
|
||||
|
||||
bool HasValidationLayers() {
|
||||
auto capabilities = std::make_unique<CapabilitiesVK>();
|
||||
return capabilities->HasLayer(kKhronosValidationLayerName);
|
||||
}
|
||||
|
||||
} // namespace vk
|
||||
|
||||
static std::set<std::string> kRequiredDeviceExtensions = {
|
||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
||||
#if FML_OS_MACOSX
|
||||
"VK_KHR_portability_subset", // For Molten VK. No define present in header.
|
||||
#endif
|
||||
};
|
||||
|
||||
std::vector<std::string> kRequiredWSIInstanceExtensions = {
|
||||
#if FML_OS_WIN
|
||||
"VK_KHR_win32_surface",
|
||||
#elif FML_OS_ANDROID
|
||||
"VK_KHR_android_surface",
|
||||
#elif FML_OS_LINUX
|
||||
"VK_KHR_xcb_surface",
|
||||
"VK_KHR_xlib_surface",
|
||||
"VK_KHR_wayland_surface",
|
||||
#elif FML_OS_MACOSX
|
||||
"VK_EXT_metal_surface",
|
||||
#endif
|
||||
};
|
||||
|
||||
#if FML_OS_MACOSX
|
||||
static const char* MVK_MACOS_SURFACE_EXT = "VK_MVK_macos_surface";
|
||||
#endif
|
||||
|
||||
static bool HasRequiredQueues(const vk::PhysicalDevice& device) {
|
||||
auto present_flags = vk::QueueFlags{};
|
||||
for (const auto& queue : device.getQueueFamilyProperties()) {
|
||||
if (queue.queueCount == 0) {
|
||||
continue;
|
||||
}
|
||||
present_flags |= queue.queueFlags;
|
||||
}
|
||||
return static_cast<VkQueueFlags>(present_flags &
|
||||
(vk::QueueFlagBits::eGraphics |
|
||||
vk::QueueFlagBits::eCompute |
|
||||
vk::QueueFlagBits::eTransfer));
|
||||
}
|
||||
|
||||
static std::vector<std::string> HasRequiredExtensions(
|
||||
const vk::PhysicalDevice& device) {
|
||||
std::set<std::string> exts;
|
||||
std::vector<std::string> missing;
|
||||
for (const auto& ext : device.enumerateDeviceExtensionProperties().value) {
|
||||
exts.insert(ext.extensionName);
|
||||
}
|
||||
for (const auto& req_ext : kRequiredDeviceExtensions) {
|
||||
if (exts.count(req_ext) != 1u) {
|
||||
missing.push_back(req_ext);
|
||||
}
|
||||
}
|
||||
return missing;
|
||||
}
|
||||
|
||||
static vk::PhysicalDeviceFeatures GetRequiredPhysicalDeviceFeatures() {
|
||||
vk::PhysicalDeviceFeatures features;
|
||||
#ifndef NDEBUG
|
||||
features.setRobustBufferAccess(true);
|
||||
#endif // NDEBUG
|
||||
return features;
|
||||
};
|
||||
|
||||
static bool HasRequiredProperties(const vk::PhysicalDevice& device) {
|
||||
auto properties = device.getProperties();
|
||||
if (!(properties.limits.framebufferColorSampleCounts &
|
||||
(vk::SampleCountFlagBits::e1 | vk::SampleCountFlagBits::e4))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool IsPhysicalDeviceCompatible(const vk::PhysicalDevice& device) {
|
||||
if (!HasRequiredQueues(device)) {
|
||||
FML_LOG(ERROR) << "Device doesn't have required queues.";
|
||||
return false;
|
||||
}
|
||||
auto missing_exts = HasRequiredExtensions(device);
|
||||
if (!missing_exts.empty()) {
|
||||
FML_LOG(ERROR) << "Device doesn't have required extensions: "
|
||||
<< fml::Join(missing_exts, ", ");
|
||||
return false;
|
||||
}
|
||||
if (!HasRequiredProperties(device)) {
|
||||
FML_LOG(ERROR) << "Device doesn't have required properties.";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return gHasValidationLayers;
|
||||
}
|
||||
|
||||
static std::optional<vk::PhysicalDevice> PickPhysicalDevice(
|
||||
const CapabilitiesVK& caps,
|
||||
const vk::Instance& instance) {
|
||||
for (const auto& device : instance.enumeratePhysicalDevices().value) {
|
||||
if (IsPhysicalDeviceCompatible(device)) {
|
||||
if (caps.GetRequiredDeviceFeatures(device).has_value()) {
|
||||
return device;
|
||||
}
|
||||
}
|
||||
@@ -219,27 +93,37 @@ std::shared_ptr<ContextVK> ContextVK::Create(
|
||||
const std::shared_ptr<const fml::Mapping>& pipeline_cache_data,
|
||||
std::shared_ptr<fml::ConcurrentTaskRunner> worker_task_runner,
|
||||
const std::string& label) {
|
||||
auto context = std::shared_ptr<ContextVK>(new ContextVK(
|
||||
proc_address_callback, //
|
||||
shader_libraries_data, //
|
||||
pipeline_cache_data, //
|
||||
std::move(worker_task_runner), //
|
||||
label //
|
||||
));
|
||||
auto context = std::shared_ptr<ContextVK>(new ContextVK());
|
||||
context->Setup(proc_address_callback, //
|
||||
shader_libraries_data, //
|
||||
pipeline_cache_data, //
|
||||
std::move(worker_task_runner), //
|
||||
label //
|
||||
);
|
||||
if (!context->IsValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
ContextVK::ContextVK(
|
||||
ContextVK::ContextVK() = default;
|
||||
|
||||
ContextVK::~ContextVK() {
|
||||
if (device_) {
|
||||
[[maybe_unused]] auto result = device_->waitIdle();
|
||||
}
|
||||
CommandPoolVK::ClearAllPools(this);
|
||||
}
|
||||
|
||||
void ContextVK::Setup(
|
||||
PFN_vkGetInstanceProcAddr proc_address_callback,
|
||||
const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries_data,
|
||||
const std::shared_ptr<const fml::Mapping>& pipeline_cache_data,
|
||||
std::shared_ptr<fml::ConcurrentTaskRunner> worker_task_runner,
|
||||
const std::string& label)
|
||||
: worker_task_runner_(std::move(worker_task_runner)) {
|
||||
TRACE_EVENT0("impeller", "ContextVK::Create");
|
||||
const std::string& label) {
|
||||
TRACE_EVENT0("impeller", "ContextVK::Setup");
|
||||
|
||||
worker_task_runner_ = std::move(worker_task_runner);
|
||||
|
||||
if (!worker_task_runner_) {
|
||||
VALIDATION_LOG << "Invalid worker task runner.";
|
||||
@@ -249,95 +133,41 @@ ContextVK::ContextVK(
|
||||
auto& dispatcher = VULKAN_HPP_DEFAULT_DISPATCHER;
|
||||
dispatcher.init(proc_address_callback);
|
||||
|
||||
auto capabilities = std::make_unique<CapabilitiesVK>();
|
||||
auto caps = std::shared_ptr<CapabilitiesVK>(new CapabilitiesVK());
|
||||
|
||||
if (!caps->IsValid()) {
|
||||
VALIDATION_LOG << "Could not determine device capabilities.";
|
||||
return;
|
||||
}
|
||||
|
||||
gHasValidationLayers = caps->AreValidationsEnabled();
|
||||
|
||||
auto enabled_layers = caps->GetRequiredLayers();
|
||||
auto enabled_extensions = caps->GetRequiredInstanceExtensions();
|
||||
|
||||
if (!enabled_layers.has_value() || !enabled_extensions.has_value()) {
|
||||
VALIDATION_LOG << "Device has insufficient capabilities.";
|
||||
return;
|
||||
}
|
||||
|
||||
vk::InstanceCreateFlags instance_flags = {};
|
||||
std::vector<const char*> enabled_layers;
|
||||
std::vector<const char*> enabled_extensions;
|
||||
|
||||
// This define may need to change into a runtime check if using SwiftShader on
|
||||
// Mac.
|
||||
#if FML_OS_MACOSX
|
||||
//----------------------------------------------------------------------------
|
||||
/// Ensure we need any Vulkan implementations that are not fully compliant
|
||||
/// with the requested Vulkan Spec. This is necessary for MoltenVK on Mac
|
||||
/// (backed by Metal).
|
||||
///
|
||||
if (!capabilities->HasExtension(
|
||||
VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME)) {
|
||||
VALIDATION_LOG << "On Mac: Required extension "
|
||||
<< VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME
|
||||
<< " absent.";
|
||||
return;
|
||||
}
|
||||
// Molten VK on Mac is not fully compliant. We opt into being OK not getting
|
||||
// back a fully compliant version of a Vulkan implementation.
|
||||
enabled_extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
|
||||
instance_flags |= vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR;
|
||||
|
||||
if (!capabilities->HasExtension(
|
||||
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
|
||||
VALIDATION_LOG << "On Mac: Required extension "
|
||||
<< VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME
|
||||
<< " absent.";
|
||||
return;
|
||||
}
|
||||
// This is dependency of VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME which
|
||||
// is a requirement for opting into Molten VK on Mac.
|
||||
enabled_extensions.push_back(
|
||||
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
|
||||
|
||||
// Required for glfw macOS surfaces.
|
||||
if (!capabilities->HasExtension(MVK_MACOS_SURFACE_EXT)) {
|
||||
VALIDATION_LOG << "On Mac: Required extension " << MVK_MACOS_SURFACE_EXT
|
||||
<< " absent.";
|
||||
return;
|
||||
}
|
||||
enabled_extensions.push_back(MVK_MACOS_SURFACE_EXT);
|
||||
#endif // FML_OS_MACOSX
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// Even though this is a WSI responsibility, require the surface extension
|
||||
/// for swapchains.
|
||||
if (!capabilities->HasExtension(VK_KHR_SURFACE_EXTENSION_NAME)) {
|
||||
VALIDATION_LOG << "Required extension " VK_KHR_SURFACE_EXTENSION_NAME
|
||||
<< " absent.";
|
||||
return;
|
||||
}
|
||||
enabled_extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// Enable WSI Instance Extensions. Having any one of these is sufficient.
|
||||
///
|
||||
bool has_wsi_extensions = false;
|
||||
for (const auto& wsi_ext : kRequiredWSIInstanceExtensions) {
|
||||
if (capabilities->HasExtension(wsi_ext)) {
|
||||
enabled_extensions.push_back(wsi_ext.c_str());
|
||||
has_wsi_extensions = true;
|
||||
}
|
||||
}
|
||||
if (!has_wsi_extensions) {
|
||||
VALIDATION_LOG
|
||||
<< "Instance doesn't have any of the required WSI extensions: "
|
||||
<< fml::Join(kRequiredWSIInstanceExtensions, ", ");
|
||||
return;
|
||||
if (std::find(enabled_extensions.value().begin(),
|
||||
enabled_extensions.value().end(),
|
||||
"VK_KHR_portability_enumeration") !=
|
||||
enabled_extensions.value().end()) {
|
||||
instance_flags |= vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// Enable any and all validation as well as debug toggles.
|
||||
///
|
||||
auto has_debug_utils = false;
|
||||
if (vk::HasValidationLayers()) {
|
||||
enabled_layers.push_back(vk::kKhronosValidationLayerName);
|
||||
if (capabilities->HasLayerExtension(vk::kKhronosValidationLayerName,
|
||||
VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
|
||||
enabled_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
has_debug_utils = true;
|
||||
} else {
|
||||
FML_LOG(ERROR) << "Vulkan debug utils are absent.";
|
||||
}
|
||||
} else {
|
||||
FML_LOG(ERROR) << "Vulkan validation layers are absent.";
|
||||
std::vector<const char*> enabled_layers_c;
|
||||
std::vector<const char*> enabled_extensions_c;
|
||||
|
||||
for (const auto& layer : enabled_layers.value()) {
|
||||
enabled_layers_c.push_back(layer.c_str());
|
||||
}
|
||||
|
||||
for (const auto& ext : enabled_extensions.value()) {
|
||||
enabled_extensions_c.push_back(ext.c_str());
|
||||
}
|
||||
|
||||
vk::ApplicationInfo application_info;
|
||||
@@ -347,52 +177,50 @@ ContextVK::ContextVK(
|
||||
application_info.setPEngineName("Impeller");
|
||||
application_info.setPApplicationName("Impeller");
|
||||
|
||||
std::vector<vk::ValidationFeatureEnableEXT> enabled_validations = {
|
||||
// vk::ValidationFeatureEnableEXT::eBestPractices,
|
||||
// vk::ValidationFeatureEnableEXT::eSynchronizationValidation,
|
||||
};
|
||||
|
||||
vk::ValidationFeaturesEXT validation;
|
||||
validation.setEnabledValidationFeatures(enabled_validations);
|
||||
|
||||
vk::InstanceCreateInfo instance_info;
|
||||
instance_info.setPEnabledLayerNames(enabled_layers);
|
||||
instance_info.setPEnabledExtensionNames(enabled_extensions);
|
||||
if (caps->AreValidationsEnabled()) {
|
||||
instance_info.pNext = &validation;
|
||||
}
|
||||
instance_info.setPEnabledLayerNames(enabled_layers_c);
|
||||
instance_info.setPEnabledExtensionNames(enabled_extensions_c);
|
||||
instance_info.setPApplicationInfo(&application_info);
|
||||
instance_info.setFlags(instance_flags);
|
||||
|
||||
auto instance = vk::createInstanceUnique(instance_info);
|
||||
if (instance.result != vk::Result::eSuccess) {
|
||||
FML_LOG(ERROR) << "Could not create instance: "
|
||||
VALIDATION_LOG << "Could not create instance: "
|
||||
<< vk::to_string(instance.result);
|
||||
return;
|
||||
}
|
||||
|
||||
dispatcher.init(instance.value.get());
|
||||
|
||||
vk::UniqueDebugUtilsMessengerEXT debug_messenger;
|
||||
//----------------------------------------------------------------------------
|
||||
/// Setup the debug report.
|
||||
///
|
||||
/// Do this as early as possible since we could use the debug report from
|
||||
/// initialization issues.
|
||||
///
|
||||
auto debug_report =
|
||||
std::make_unique<DebugReportVK>(*caps, instance.value.get());
|
||||
|
||||
if (has_debug_utils) {
|
||||
vk::DebugUtilsMessengerCreateInfoEXT debug_messenger_info;
|
||||
debug_messenger_info.messageSeverity =
|
||||
vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
|
||||
vk::DebugUtilsMessageSeverityFlagBitsEXT::eError;
|
||||
debug_messenger_info.messageType =
|
||||
vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
|
||||
vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance |
|
||||
vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation;
|
||||
debug_messenger_info.pUserData = nullptr;
|
||||
debug_messenger_info.pfnUserCallback = DebugUtilsMessengerCallback;
|
||||
|
||||
auto debug_messenger_result =
|
||||
instance.value->createDebugUtilsMessengerEXTUnique(
|
||||
debug_messenger_info);
|
||||
|
||||
if (debug_messenger_result.result != vk::Result::eSuccess) {
|
||||
FML_LOG(ERROR) << "Could not create debug messenger: "
|
||||
<< vk::to_string(debug_messenger_result.result);
|
||||
return;
|
||||
}
|
||||
|
||||
debug_messenger = std::move(debug_messenger_result.value);
|
||||
if (!debug_report->IsValid()) {
|
||||
VALIDATION_LOG << "Could not setup debug report.";
|
||||
return;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// Pick the physical device.
|
||||
///
|
||||
auto physical_device = PickPhysicalDevice(instance.value.get());
|
||||
auto physical_device = PickPhysicalDevice(*caps, instance.value.get());
|
||||
if (!physical_device.has_value()) {
|
||||
VALIDATION_LOG << "No valid Vulkan device found.";
|
||||
return;
|
||||
@@ -408,29 +236,44 @@ ContextVK::ContextVK(
|
||||
auto compute_queue =
|
||||
PickQueue(physical_device.value(), vk::QueueFlagBits::eCompute);
|
||||
|
||||
physical_device_ = physical_device.value();
|
||||
|
||||
if (!graphics_queue.has_value() || !transfer_queue.has_value() ||
|
||||
!compute_queue.has_value()) {
|
||||
VALIDATION_LOG << "Could not pick device queues.";
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<const char*> required_extensions;
|
||||
for (const auto& ext : kRequiredDeviceExtensions) {
|
||||
required_extensions.push_back(ext.data());
|
||||
//----------------------------------------------------------------------------
|
||||
/// Create the logical device.
|
||||
///
|
||||
auto enabled_device_extensions =
|
||||
caps->GetRequiredDeviceExtensions(physical_device.value());
|
||||
if (!enabled_device_extensions.has_value()) {
|
||||
// This shouldn't happen since we already did device selection. But doesn't
|
||||
// hurt to check again.
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<const char*> enabled_device_extensions_c;
|
||||
for (const auto& ext : enabled_device_extensions.value()) {
|
||||
enabled_device_extensions_c.push_back(ext.c_str());
|
||||
}
|
||||
|
||||
const auto queue_create_infos = GetQueueCreateInfos(
|
||||
{graphics_queue.value(), compute_queue.value(), transfer_queue.value()});
|
||||
|
||||
const auto required_features = GetRequiredPhysicalDeviceFeatures();
|
||||
const auto required_features =
|
||||
caps->GetRequiredDeviceFeatures(physical_device.value());
|
||||
if (!required_features.has_value()) {
|
||||
// This shouldn't happen since the device can't be picked if this was not
|
||||
// true. But doesn't hurt to check.
|
||||
return;
|
||||
}
|
||||
|
||||
vk::DeviceCreateInfo device_info;
|
||||
|
||||
device_info.setQueueCreateInfos(queue_create_infos);
|
||||
device_info.setPEnabledExtensionNames(required_extensions);
|
||||
device_info.setPEnabledFeatures(&required_features);
|
||||
device_info.setPEnabledExtensionNames(enabled_device_extensions_c);
|
||||
device_info.setPEnabledFeatures(&required_features.value());
|
||||
// Device layers are deprecated and ignored.
|
||||
|
||||
auto device = physical_device->createDeviceUnique(device_info);
|
||||
@@ -439,6 +282,14 @@ ContextVK::ContextVK(
|
||||
return;
|
||||
}
|
||||
|
||||
if (!caps->SetDevice(physical_device.value())) {
|
||||
VALIDATION_LOG << "Capabilities could not be updated.";
|
||||
return;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// Create the allocator.
|
||||
///
|
||||
auto allocator = std::shared_ptr<AllocatorVK>(new AllocatorVK(
|
||||
weak_from_this(), //
|
||||
application_info.apiVersion, //
|
||||
@@ -479,6 +330,9 @@ ContextVK::ContextVK(
|
||||
return;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// Setup the work queues.
|
||||
///
|
||||
auto work_queue = WorkQueueCommon::Create();
|
||||
|
||||
if (!work_queue) {
|
||||
@@ -487,47 +341,12 @@ ContextVK::ContextVK(
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// Setup the command pool.
|
||||
/// Create the fence waiter.
|
||||
///
|
||||
vk::CommandPoolCreateInfo graphics_command_pool_info;
|
||||
graphics_command_pool_info.queueFamilyIndex = graphics_queue->index;
|
||||
graphics_command_pool_info.flags = vk::CommandPoolCreateFlagBits::eTransient;
|
||||
auto graphics_command_pool =
|
||||
device.value->createCommandPoolUnique(graphics_command_pool_info);
|
||||
if (graphics_command_pool.result != vk::Result::eSuccess) {
|
||||
VALIDATION_LOG << "Could not create graphics command pool.";
|
||||
return;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// Setup the descriptor pool. This needs to be dynamic but we just allocate a
|
||||
/// jumbo pool and hope for the best.
|
||||
///
|
||||
constexpr size_t kPoolSize = 1024 * 3;
|
||||
|
||||
std::vector<vk::DescriptorPoolSize> pool_sizes = {
|
||||
{vk::DescriptorType::eSampler, kPoolSize},
|
||||
{vk::DescriptorType::eCombinedImageSampler, kPoolSize},
|
||||
{vk::DescriptorType::eSampledImage, kPoolSize},
|
||||
{vk::DescriptorType::eStorageImage, kPoolSize},
|
||||
{vk::DescriptorType::eUniformTexelBuffer, kPoolSize},
|
||||
{vk::DescriptorType::eStorageTexelBuffer, kPoolSize},
|
||||
{vk::DescriptorType::eUniformBuffer, kPoolSize},
|
||||
{vk::DescriptorType::eStorageBuffer, kPoolSize},
|
||||
{vk::DescriptorType::eUniformBufferDynamic, kPoolSize},
|
||||
{vk::DescriptorType::eStorageBufferDynamic, kPoolSize},
|
||||
{vk::DescriptorType::eInputAttachment, kPoolSize},
|
||||
};
|
||||
vk::DescriptorPoolCreateInfo pool_info = {
|
||||
vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet, // flags
|
||||
static_cast<uint32_t>(pool_sizes.size() * kPoolSize), // max sets
|
||||
static_cast<uint32_t>(pool_sizes.size()), // pool sizes count
|
||||
pool_sizes.data() // pool sizes
|
||||
};
|
||||
|
||||
auto descriptor_pool = device.value->createDescriptorPoolUnique(pool_info);
|
||||
if (descriptor_pool.result != vk::Result::eSuccess) {
|
||||
VALIDATION_LOG << "Unable to create a descriptor pool";
|
||||
auto fence_waiter =
|
||||
std::shared_ptr<FenceWaiterVK>(new FenceWaiterVK(device.value.get()));
|
||||
if (!fence_waiter->IsValid()) {
|
||||
VALIDATION_LOG << "Could not create fence waiter.";
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -535,7 +354,8 @@ ContextVK::ContextVK(
|
||||
/// All done!
|
||||
///
|
||||
instance_ = std::move(instance.value);
|
||||
debug_messenger_ = std::move(debug_messenger);
|
||||
debug_report_ = std::move(debug_report);
|
||||
physical_device_ = physical_device.value();
|
||||
device_ = std::move(device.value);
|
||||
allocator_ = std::move(allocator);
|
||||
shader_library_ = std::move(shader_library);
|
||||
@@ -548,27 +368,21 @@ ContextVK::ContextVK(
|
||||
device_->getQueue(compute_queue->family, compute_queue->index);
|
||||
transfer_queue_ =
|
||||
device_->getQueue(transfer_queue->family, transfer_queue->index);
|
||||
device_capabilities_ =
|
||||
DeviceCapabilitiesBuilder()
|
||||
.SetHasThreadingRestrictions(false)
|
||||
.SetSupportsOffscreenMSAA(true)
|
||||
.SetSupportsSSBO(false)
|
||||
.SetSupportsTextureToTextureBlits(true)
|
||||
.SetSupportsFramebufferFetch(false)
|
||||
.SetDefaultColorFormat(PixelFormat::kB8G8R8A8UNormInt)
|
||||
.SetDefaultStencilFormat(PixelFormat::kS8UInt)
|
||||
// TODO(110622): detect this and enable.
|
||||
.SetSupportsCompute(false, false)
|
||||
.Build();
|
||||
graphics_command_pool_ = std::move(graphics_command_pool.value);
|
||||
descriptor_pool_ = std::move(descriptor_pool.value);
|
||||
graphics_queue_info_ = graphics_queue.value();
|
||||
compute_queue_info_ = compute_queue.value();
|
||||
transfer_queue_info_ = transfer_queue.value();
|
||||
device_capabilities_ = std::move(caps);
|
||||
fence_waiter_ = std::move(fence_waiter);
|
||||
is_valid_ = true;
|
||||
}
|
||||
|
||||
ContextVK::~ContextVK() {
|
||||
if (device_) {
|
||||
[[maybe_unused]] auto result = device_->waitIdle();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/// Label all the relevant objects. This happens after setup so that the debug
|
||||
/// messengers have had a chance to be setup.
|
||||
///
|
||||
SetDebugName(device_.get(), device_.get(), "ImpellerDevice");
|
||||
SetDebugName(device_.get(), graphics_queue_, "ImpellerGraphicsQ");
|
||||
SetDebugName(device_.get(), compute_queue_, "ImpellerComputeQ");
|
||||
SetDebugName(device_.get(), transfer_queue_, "ImpellerTransferQ");
|
||||
}
|
||||
|
||||
bool ContextVK::IsValid() const {
|
||||
@@ -597,9 +411,13 @@ std::shared_ptr<WorkQueue> ContextVK::GetWorkQueue() const {
|
||||
}
|
||||
|
||||
std::shared_ptr<CommandBuffer> ContextVK::CreateCommandBuffer() const {
|
||||
auto encoder = CreateGraphicsCommandEncoder();
|
||||
if (!encoder) {
|
||||
return nullptr;
|
||||
}
|
||||
return std::shared_ptr<CommandBufferVK>(
|
||||
new CommandBufferVK(shared_from_this(), //
|
||||
CreateGraphicsCommandEncoder()) //
|
||||
new CommandBufferVK(shared_from_this(), //
|
||||
std::move(encoder)) //
|
||||
);
|
||||
}
|
||||
|
||||
@@ -646,37 +464,37 @@ bool ContextVK::SetWindowSurface(vk::UniqueSurfaceKHR surface) {
|
||||
return true;
|
||||
}
|
||||
|
||||
PixelFormat ContextVK::GetColorAttachmentPixelFormat() const {
|
||||
return swapchain_ ? ToPixelFormat(swapchain_->GetSurfaceFormat())
|
||||
: PixelFormat::kB8G8R8A8UNormInt;
|
||||
}
|
||||
|
||||
const IDeviceCapabilities& ContextVK::GetDeviceCapabilities() const {
|
||||
return *device_capabilities_;
|
||||
const std::shared_ptr<const Capabilities>& ContextVK::GetCapabilities() const {
|
||||
return device_capabilities_;
|
||||
}
|
||||
|
||||
vk::Queue ContextVK::GetGraphicsQueue() const {
|
||||
return graphics_queue_;
|
||||
}
|
||||
|
||||
vk::CommandPool ContextVK::GetGraphicsCommandPool() const {
|
||||
return *graphics_command_pool_;
|
||||
}
|
||||
|
||||
vk::DescriptorPool ContextVK::GetDescriptorPool() const {
|
||||
return *descriptor_pool_;
|
||||
QueueVK ContextVK::GetGraphicsQueueInfo() const {
|
||||
return graphics_queue_info_;
|
||||
}
|
||||
|
||||
vk::PhysicalDevice ContextVK::GetPhysicalDevice() const {
|
||||
return physical_device_;
|
||||
}
|
||||
|
||||
std::shared_ptr<FenceWaiterVK> ContextVK::GetFenceWaiter() const {
|
||||
return fence_waiter_;
|
||||
}
|
||||
|
||||
std::unique_ptr<CommandEncoderVK> ContextVK::CreateGraphicsCommandEncoder()
|
||||
const {
|
||||
auto tls_pool = CommandPoolVK::GetThreadLocal(this);
|
||||
if (!tls_pool) {
|
||||
return nullptr;
|
||||
}
|
||||
auto encoder = std::unique_ptr<CommandEncoderVK>(new CommandEncoderVK(
|
||||
*device_, //
|
||||
graphics_queue_, //
|
||||
*graphics_command_pool_ //
|
||||
*device_, //
|
||||
graphics_queue_, //
|
||||
tls_pool, //
|
||||
fence_waiter_ //
|
||||
));
|
||||
if (!encoder->IsValid()) {
|
||||
return nullptr;
|
||||
|
||||
@@ -15,24 +15,18 @@
|
||||
#include "impeller/renderer/backend/vulkan/shader_library_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/swapchain_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/vk.h"
|
||||
#include "impeller/renderer/capabilities.h"
|
||||
#include "impeller/renderer/context.h"
|
||||
#include "impeller/renderer/device_capabilities.h"
|
||||
#include "impeller/renderer/formats.h"
|
||||
#include "impeller/renderer/surface.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
namespace vk {
|
||||
|
||||
// TODO(csg): Move this to its own TU for validations.
|
||||
constexpr const char* kKhronosValidationLayerName =
|
||||
"VK_LAYER_KHRONOS_validation";
|
||||
|
||||
bool HasValidationLayers();
|
||||
|
||||
} // namespace vk
|
||||
|
||||
class CommandEncoderVK;
|
||||
class DebugReportVK;
|
||||
class FenceWaiterVK;
|
||||
|
||||
class ContextVK final : public Context, public BackendCast<ContextVK, Context> {
|
||||
public:
|
||||
@@ -64,14 +58,11 @@ class ContextVK final : public Context, public BackendCast<ContextVK, Context> {
|
||||
// |Context|
|
||||
std::shared_ptr<CommandBuffer> CreateCommandBuffer() const override;
|
||||
|
||||
// |Context|
|
||||
PixelFormat GetColorAttachmentPixelFormat() const override;
|
||||
|
||||
// |Context|
|
||||
std::shared_ptr<WorkQueue> GetWorkQueue() const override;
|
||||
|
||||
// |Context|
|
||||
const IDeviceCapabilities& GetDeviceCapabilities() const override;
|
||||
const std::shared_ptr<const Capabilities>& GetCapabilities() const override;
|
||||
|
||||
template <typename T>
|
||||
bool SetDebugName(T handle, std::string_view label) const {
|
||||
@@ -82,22 +73,19 @@ class ContextVK final : public Context, public BackendCast<ContextVK, Context> {
|
||||
static bool SetDebugName(vk::Device device,
|
||||
T handle,
|
||||
std::string_view label) {
|
||||
if (!vk::HasValidationLayers()) {
|
||||
if (!HasValidationLayers()) {
|
||||
// No-op if validation layers are not enabled.
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t handle_ptr =
|
||||
reinterpret_cast<uint64_t>(static_cast<typename T::NativeType>(handle));
|
||||
auto c_handle = static_cast<typename T::CType>(handle);
|
||||
|
||||
std::string label_str = std::string(label);
|
||||
auto ret = device.setDebugUtilsObjectNameEXT(
|
||||
vk::DebugUtilsObjectNameInfoEXT()
|
||||
.setObjectType(T::objectType)
|
||||
.setObjectHandle(handle_ptr)
|
||||
.setPObjectName(label_str.c_str()));
|
||||
vk::DebugUtilsObjectNameInfoEXT info;
|
||||
info.objectType = T::objectType;
|
||||
info.pObjectName = label.data();
|
||||
info.objectHandle = reinterpret_cast<decltype(info.objectHandle)>(c_handle);
|
||||
|
||||
if (ret != vk::Result::eSuccess) {
|
||||
if (device.setDebugUtilsObjectNameEXT(info) != vk::Result::eSuccess) {
|
||||
VALIDATION_LOG << "Unable to set debug name: " << label;
|
||||
return false;
|
||||
}
|
||||
@@ -119,16 +107,16 @@ class ContextVK final : public Context, public BackendCast<ContextVK, Context> {
|
||||
|
||||
vk::Queue GetGraphicsQueue() const;
|
||||
|
||||
vk::CommandPool GetGraphicsCommandPool() const;
|
||||
|
||||
vk::DescriptorPool GetDescriptorPool() const;
|
||||
QueueVK GetGraphicsQueueInfo() const;
|
||||
|
||||
vk::PhysicalDevice GetPhysicalDevice() const;
|
||||
|
||||
std::shared_ptr<FenceWaiterVK> GetFenceWaiter() const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<fml::ConcurrentTaskRunner> worker_task_runner_;
|
||||
vk::UniqueInstance instance_;
|
||||
vk::UniqueDebugUtilsMessengerEXT debug_messenger_;
|
||||
std::unique_ptr<DebugReportVK> debug_report_;
|
||||
vk::PhysicalDevice physical_device_;
|
||||
vk::UniqueDevice device_;
|
||||
std::shared_ptr<Allocator> allocator_;
|
||||
@@ -138,14 +126,19 @@ class ContextVK final : public Context, public BackendCast<ContextVK, Context> {
|
||||
vk::Queue graphics_queue_ = {};
|
||||
vk::Queue compute_queue_ = {};
|
||||
vk::Queue transfer_queue_ = {};
|
||||
QueueVK graphics_queue_info_ = {};
|
||||
QueueVK compute_queue_info_ = {};
|
||||
QueueVK transfer_queue_info_ = {};
|
||||
std::shared_ptr<SwapchainVK> swapchain_;
|
||||
std::shared_ptr<WorkQueue> work_queue_;
|
||||
std::unique_ptr<IDeviceCapabilities> device_capabilities_;
|
||||
vk::UniqueCommandPool graphics_command_pool_;
|
||||
vk::UniqueDescriptorPool descriptor_pool_;
|
||||
std::shared_ptr<const Capabilities> device_capabilities_;
|
||||
std::shared_ptr<FenceWaiterVK> fence_waiter_;
|
||||
|
||||
bool is_valid_ = false;
|
||||
|
||||
ContextVK(
|
||||
ContextVK();
|
||||
|
||||
void Setup(
|
||||
PFN_vkGetInstanceProcAddr proc_address_callback,
|
||||
const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries_data,
|
||||
const std::shared_ptr<const fml::Mapping>& pipeline_cache_data,
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "impeller/renderer/backend/vulkan/debug_report_vk.h"
|
||||
|
||||
#include "impeller/renderer/backend/vulkan/capabilities_vk.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
DebugReportVK::DebugReportVK(const CapabilitiesVK& caps,
|
||||
const vk::Instance& instance) {
|
||||
if (!caps.AreValidationsEnabled()) {
|
||||
is_valid_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
vk::DebugUtilsMessengerCreateInfoEXT messenger_info;
|
||||
messenger_info.messageSeverity =
|
||||
vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
|
||||
vk::DebugUtilsMessageSeverityFlagBitsEXT::eError;
|
||||
messenger_info.messageType =
|
||||
vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
|
||||
vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance |
|
||||
vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation;
|
||||
messenger_info.pUserData = this;
|
||||
messenger_info.pfnUserCallback = DebugUtilsMessengerCallback;
|
||||
|
||||
auto messenger = instance.createDebugUtilsMessengerEXTUnique(messenger_info);
|
||||
|
||||
if (messenger.result != vk::Result::eSuccess) {
|
||||
FML_LOG(ERROR) << "Could not create debug messenger: "
|
||||
<< vk::to_string(messenger.result);
|
||||
return;
|
||||
}
|
||||
|
||||
messenger_ = std::move(messenger.value);
|
||||
is_valid_ = true;
|
||||
}
|
||||
|
||||
DebugReportVK::~DebugReportVK() = default;
|
||||
|
||||
bool DebugReportVK::IsValid() const {
|
||||
return is_valid_;
|
||||
}
|
||||
|
||||
static std::string JoinLabels(const VkDebugUtilsLabelEXT* labels,
|
||||
size_t count) {
|
||||
std::stringstream stream;
|
||||
for (size_t i = 0u; i < count; i++) {
|
||||
stream << labels[i].pLabelName;
|
||||
if (i != count - 1u) {
|
||||
stream << ", ";
|
||||
}
|
||||
}
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
static std::string JoinVKDebugUtilsObjectNameInfoEXT(
|
||||
const VkDebugUtilsObjectNameInfoEXT* names,
|
||||
size_t count) {
|
||||
std::stringstream stream;
|
||||
for (size_t i = 0u; i < count; i++) {
|
||||
stream << vk::to_string(vk::ObjectType(names[i].objectType)) << " ["
|
||||
<< names[i].objectHandle << "] [";
|
||||
if (names[i].pObjectName != nullptr) {
|
||||
stream << names[i].pObjectName;
|
||||
} else {
|
||||
stream << "UNNAMED";
|
||||
}
|
||||
stream << "]";
|
||||
if (i != count - 1u) {
|
||||
stream << ", ";
|
||||
}
|
||||
}
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkBool32 VKAPI_CALL DebugReportVK::DebugUtilsMessengerCallback(
|
||||
VkDebugUtilsMessageSeverityFlagBitsEXT severity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT type,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* callback_data,
|
||||
void* debug_report) {
|
||||
auto result =
|
||||
reinterpret_cast<DebugReportVK*>(debug_report)
|
||||
->OnDebugCallback(
|
||||
static_cast<vk::DebugUtilsMessageSeverityFlagBitsEXT>(
|
||||
severity), //
|
||||
static_cast<vk::DebugUtilsMessageTypeFlagsEXT>(type), //
|
||||
callback_data //
|
||||
);
|
||||
switch (result) {
|
||||
case Result::kContinue:
|
||||
return VK_FALSE;
|
||||
case Result::kAbort:
|
||||
return VK_TRUE;
|
||||
}
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
DebugReportVK::Result DebugReportVK::OnDebugCallback(
|
||||
vk::DebugUtilsMessageSeverityFlagBitsEXT severity,
|
||||
vk::DebugUtilsMessageTypeFlagsEXT type,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* data) {
|
||||
// Issue in older versions of the SDK.
|
||||
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/3554
|
||||
if (strstr(data->pMessageIdName, "CoreValidation-Shader-OutputNotConsumed") !=
|
||||
nullptr) {
|
||||
return Result::kContinue;
|
||||
}
|
||||
|
||||
// This is a real error but we can't fix it due to our headers being too
|
||||
// old. More more details see:
|
||||
// https://vulkan.lunarg.com/doc/view/1.3.224.1/mac/1.3-extensions/vkspec.html#VUID-VkImageViewCreateInfo-imageViewFormatSwizzle-04465
|
||||
// This validation error currently only trips on macOS due to the use of
|
||||
// texture swizzles.
|
||||
if (data->messageIdNumber == static_cast<int32_t>(0x82ae5050)) {
|
||||
return Result::kContinue;
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> items;
|
||||
|
||||
items.emplace_back("Severity", vk::to_string(severity));
|
||||
|
||||
items.emplace_back("Type", vk::to_string(type));
|
||||
|
||||
if (data->pMessageIdName) {
|
||||
items.emplace_back("ID Name", data->pMessageIdName);
|
||||
}
|
||||
|
||||
items.emplace_back("ID Number", std::to_string(data->messageIdNumber));
|
||||
|
||||
if (auto queues = JoinLabels(data->pQueueLabels, data->queueLabelCount);
|
||||
!queues.empty()) {
|
||||
items.emplace_back("Queue Breadcrumbs", std::move(queues));
|
||||
} else {
|
||||
items.emplace_back("Queue Breadcrumbs", "[NONE]");
|
||||
}
|
||||
|
||||
if (auto cmd_bufs = JoinLabels(data->pCmdBufLabels, data->cmdBufLabelCount);
|
||||
!cmd_bufs.empty()) {
|
||||
items.emplace_back("CMD Buffer Breadcrumbs", std::move(cmd_bufs));
|
||||
} else {
|
||||
items.emplace_back("CMD Buffer Breadcrumbs", "[NONE]");
|
||||
}
|
||||
|
||||
if (auto related =
|
||||
JoinVKDebugUtilsObjectNameInfoEXT(data->pObjects, data->objectCount);
|
||||
!related.empty()) {
|
||||
items.emplace_back("Related Objects", std::move(related));
|
||||
}
|
||||
|
||||
if (data->pMessage) {
|
||||
items.emplace_back("Trigger", data->pMessage);
|
||||
}
|
||||
|
||||
size_t padding = 0;
|
||||
|
||||
for (const auto& item : items) {
|
||||
padding = std::max(padding, item.first.size());
|
||||
}
|
||||
|
||||
padding += 1;
|
||||
|
||||
std::stringstream stream;
|
||||
|
||||
stream << std::endl;
|
||||
|
||||
stream << "--- Vulkan Debug Report ----------------------------------------";
|
||||
|
||||
stream << std::endl;
|
||||
|
||||
for (const auto& item : items) {
|
||||
stream << "| " << std::setw(static_cast<int>(padding)) << item.first
|
||||
<< std::setw(0) << ": " << item.second << std::endl;
|
||||
}
|
||||
|
||||
stream << "-----------------------------------------------------------------";
|
||||
|
||||
if (type == vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance) {
|
||||
FML_LOG(INFO) << stream.str();
|
||||
} else {
|
||||
VALIDATION_LOG << stream.str();
|
||||
}
|
||||
|
||||
return Result::kAbort;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/renderer/backend/vulkan/vk.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
class CapabilitiesVK;
|
||||
|
||||
class DebugReportVK {
|
||||
public:
|
||||
DebugReportVK(const CapabilitiesVK& caps, const vk::Instance& instance);
|
||||
|
||||
~DebugReportVK();
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
private:
|
||||
vk::UniqueDebugUtilsMessengerEXT messenger_;
|
||||
bool is_valid_ = false;
|
||||
|
||||
enum class Result {
|
||||
kContinue,
|
||||
kAbort,
|
||||
};
|
||||
|
||||
Result OnDebugCallback(vk::DebugUtilsMessageSeverityFlagBitsEXT severity,
|
||||
vk::DebugUtilsMessageTypeFlagsEXT type,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* data);
|
||||
|
||||
static VKAPI_ATTR VkBool32 VKAPI_CALL DebugUtilsMessengerCallback(
|
||||
VkDebugUtilsMessageSeverityFlagBitsEXT severity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT type,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* callback_data,
|
||||
void* user_data);
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(DebugReportVK);
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
@@ -0,0 +1,74 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "impeller/renderer/backend/vulkan/descriptor_pool_vk.h"
|
||||
|
||||
#include "flutter/fml/trace_event.h"
|
||||
#include "impeller/base/allocation.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
DescriptorPoolVK::DescriptorPoolVK(vk::Device device) : device_(device) {}
|
||||
|
||||
DescriptorPoolVK::~DescriptorPoolVK() = default;
|
||||
|
||||
static vk::UniqueDescriptorPool CreatePool(const vk::Device& device,
|
||||
uint32_t pool_count) {
|
||||
TRACE_EVENT0("impeller", "CreateDescriptorPool");
|
||||
std::vector<vk::DescriptorPoolSize> pools = {
|
||||
{vk::DescriptorType::eCombinedImageSampler, pool_count},
|
||||
{vk::DescriptorType::eUniformBuffer, pool_count},
|
||||
};
|
||||
|
||||
vk::DescriptorPoolCreateInfo pool_info;
|
||||
pool_info.setMaxSets(pools.size() * pool_count);
|
||||
pool_info.setPoolSizes(pools);
|
||||
|
||||
auto [result, pool] = device.createDescriptorPoolUnique(pool_info);
|
||||
if (result != vk::Result::eSuccess) {
|
||||
VALIDATION_LOG << "Unable to create a descriptor pool";
|
||||
}
|
||||
return std::move(pool);
|
||||
}
|
||||
|
||||
std::optional<vk::DescriptorSet> DescriptorPoolVK::AllocateDescriptorSet(
|
||||
const vk::DescriptorSetLayout& layout) {
|
||||
auto pool = GetDescriptorPool();
|
||||
if (!pool) {
|
||||
return std::nullopt;
|
||||
}
|
||||
vk::DescriptorSetAllocateInfo set_info;
|
||||
set_info.setDescriptorPool(pool.value());
|
||||
set_info.setSetLayouts(layout);
|
||||
auto [result, sets] = device_.allocateDescriptorSets(set_info);
|
||||
if (result == vk::Result::eErrorOutOfPoolMemory) {
|
||||
return GrowPool() ? AllocateDescriptorSet(layout) : std::nullopt;
|
||||
}
|
||||
if (result != vk::Result::eSuccess) {
|
||||
VALIDATION_LOG << "Could not allocate descriptor sets: "
|
||||
<< vk::to_string(result);
|
||||
return std::nullopt;
|
||||
}
|
||||
return sets[0];
|
||||
}
|
||||
|
||||
std::optional<vk::DescriptorPool> DescriptorPoolVK::GetDescriptorPool() {
|
||||
if (pools_.empty()) {
|
||||
return GrowPool() ? GetDescriptorPool() : std::nullopt;
|
||||
}
|
||||
return *pools_.back();
|
||||
}
|
||||
|
||||
bool DescriptorPoolVK::GrowPool() {
|
||||
const auto new_pool_size = Allocation::NextPowerOfTwoSize(pool_size_ + 1u);
|
||||
auto new_pool = CreatePool(device_, new_pool_size);
|
||||
if (!new_pool) {
|
||||
return false;
|
||||
}
|
||||
pool_size_ = new_pool_size;
|
||||
pools_.push(std::move(new_pool));
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <queue>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/renderer/backend/vulkan/vk.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @brief A short-lived dynamically-sized descriptor pool. Descriptors
|
||||
/// from this pool don't need to be freed individually. Instead, the
|
||||
/// pool must be collected after all the descriptors allocated from
|
||||
/// it are done being used.
|
||||
///
|
||||
/// The pool or it's descriptors may not be accessed from multiple
|
||||
/// threads.
|
||||
///
|
||||
/// Encoders create pools as necessary as they have the same
|
||||
/// threading and lifecycle restrictions.
|
||||
///
|
||||
class DescriptorPoolVK {
|
||||
public:
|
||||
explicit DescriptorPoolVK(vk::Device device);
|
||||
|
||||
~DescriptorPoolVK();
|
||||
|
||||
std::optional<vk::DescriptorSet> AllocateDescriptorSet(
|
||||
const vk::DescriptorSetLayout& layout);
|
||||
|
||||
private:
|
||||
const vk::Device device_;
|
||||
uint32_t pool_size_ = 31u;
|
||||
std::queue<vk::UniqueDescriptorPool> pools_;
|
||||
|
||||
std::optional<vk::DescriptorPool> GetDescriptorPool();
|
||||
|
||||
bool GrowPool();
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(DescriptorPoolVK);
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
@@ -67,7 +67,7 @@ bool DeviceBufferVK::SetLabel(const std::string& label, Range range) {
|
||||
return SetLabel(label);
|
||||
}
|
||||
|
||||
vk::Buffer DeviceBufferVK::GetVKBufferHandle() const {
|
||||
vk::Buffer DeviceBufferVK::GetBuffer() const {
|
||||
return buffer_;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ class DeviceBufferVK final : public DeviceBuffer,
|
||||
// |DeviceBuffer|
|
||||
~DeviceBufferVK() override;
|
||||
|
||||
vk::Buffer GetVKBufferHandle() const;
|
||||
vk::Buffer GetBuffer() const;
|
||||
|
||||
private:
|
||||
friend class AllocatorVK;
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "impeller/renderer/backend/vulkan/fence_waiter_vk.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "flutter/fml/thread.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
FenceWaiterVK::FenceWaiterVK(vk::Device device) : device_(device) {
|
||||
waiter_thread_ = std::make_unique<std::thread>([&]() { Main(); });
|
||||
is_valid_ = true;
|
||||
}
|
||||
|
||||
FenceWaiterVK::~FenceWaiterVK() {
|
||||
Terminate();
|
||||
if (waiter_thread_) {
|
||||
waiter_thread_->join();
|
||||
}
|
||||
}
|
||||
|
||||
bool FenceWaiterVK::IsValid() const {
|
||||
return is_valid_;
|
||||
}
|
||||
|
||||
bool FenceWaiterVK::AddFence(vk::UniqueFence fence,
|
||||
const fml::closure& callback) {
|
||||
if (!IsValid() || !fence || !callback) {
|
||||
return false;
|
||||
}
|
||||
{
|
||||
std::scoped_lock lock(wait_set_mutex_);
|
||||
wait_set_[MakeSharedVK(std::move(fence))] = callback;
|
||||
}
|
||||
wait_set_cv_.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
void FenceWaiterVK::Main() {
|
||||
fml::Thread::SetCurrentThreadName(
|
||||
fml::Thread::ThreadConfig{"io.flutter.impeller.fence_waiter"});
|
||||
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
while (true) {
|
||||
std::unique_lock lock(wait_set_mutex_);
|
||||
|
||||
wait_set_cv_.wait(lock, [&]() { return !wait_set_.empty() || terminate_; });
|
||||
|
||||
auto wait_set = TrimAndCreateWaitSetLocked();
|
||||
|
||||
lock.unlock();
|
||||
|
||||
if (!wait_set.has_value()) {
|
||||
break;
|
||||
}
|
||||
if (wait_set->empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto result = device_.waitForFences(
|
||||
wait_set->size(), // fences count
|
||||
wait_set->data(), // fences
|
||||
false, // wait for all
|
||||
std::chrono::nanoseconds{100ms}.count() // timeout (ns)
|
||||
);
|
||||
if (!(result == vk::Result::eSuccess || result == vk::Result::eTimeout)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<std::vector<vk::Fence>>
|
||||
FenceWaiterVK::TrimAndCreateWaitSetLocked() {
|
||||
if (terminate_) {
|
||||
return std::nullopt;
|
||||
}
|
||||
std::vector<vk::Fence> fences;
|
||||
fences.reserve(wait_set_.size());
|
||||
for (auto it = wait_set_.begin(); it != wait_set_.end();) {
|
||||
switch (device_.getFenceStatus(it->first->Get())) {
|
||||
case vk::Result::eSuccess: // Signalled.
|
||||
it->second();
|
||||
it = wait_set_.erase(it);
|
||||
break;
|
||||
case vk::Result::eNotReady: // Un-signalled.
|
||||
fences.push_back(it->first->Get());
|
||||
it++;
|
||||
break;
|
||||
default:
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
return fences;
|
||||
}
|
||||
|
||||
void FenceWaiterVK::Terminate() {
|
||||
{
|
||||
std::scoped_lock lock(wait_set_mutex_);
|
||||
terminate_ = true;
|
||||
}
|
||||
wait_set_cv_.notify_one();
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "flutter/fml/closure.h"
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/base/thread.h"
|
||||
#include "impeller/renderer/backend/vulkan/shared_object_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/vk.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
class ContextVK;
|
||||
|
||||
class FenceWaiterVK {
|
||||
public:
|
||||
~FenceWaiterVK();
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
void Terminate();
|
||||
|
||||
bool AddFence(vk::UniqueFence fence, const fml::closure& callback);
|
||||
|
||||
private:
|
||||
friend class ContextVK;
|
||||
|
||||
const vk::Device device_;
|
||||
std::unique_ptr<std::thread> waiter_thread_;
|
||||
std::mutex wait_set_mutex_;
|
||||
std::condition_variable wait_set_cv_;
|
||||
std::unordered_map<SharedHandleVK<vk::Fence>, fml::closure> wait_set_;
|
||||
bool terminate_ = false;
|
||||
bool is_valid_ = false;
|
||||
|
||||
explicit FenceWaiterVK(vk::Device device);
|
||||
|
||||
void Main();
|
||||
|
||||
std::optional<std::vector<vk::Fence>> TrimAndCreateWaitSetLocked();
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(FenceWaiterVK);
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/renderer/backend/vulkan/vk.h"
|
||||
#include "impeller/renderer/descriptor_set_layout.h"
|
||||
#include "impeller/renderer/formats.h"
|
||||
#include "impeller/renderer/shader_types.h"
|
||||
#include "vulkan/vulkan_enums.hpp"
|
||||
@@ -205,6 +204,8 @@ constexpr vk::SampleCountFlagBits ToVKSampleCount(SampleCount sample_count) {
|
||||
case SampleCount::kCount4:
|
||||
return vk::SampleCountFlagBits::e4;
|
||||
}
|
||||
|
||||
FML_UNREACHABLE();
|
||||
}
|
||||
|
||||
constexpr vk::Filter ToVKSamplerMinMagFilter(MinMagFilter filter) {
|
||||
@@ -269,7 +270,7 @@ constexpr vk::DescriptorSetLayoutBinding ToVKDescriptorSetLayoutBinding(
|
||||
const DescriptorSetLayout& layout) {
|
||||
vk::DescriptorSetLayoutBinding binding;
|
||||
binding.binding = layout.binding;
|
||||
binding.descriptorCount = layout.descriptor_count;
|
||||
binding.descriptorCount = 1u;
|
||||
vk::DescriptorType desc_type = vk::DescriptorType();
|
||||
switch (layout.descriptor_type) {
|
||||
case DescriptorType::kSampledImage:
|
||||
@@ -546,9 +547,60 @@ constexpr uint32_t ToArrayLayerCount(TextureType type) {
|
||||
FML_UNREACHABLE();
|
||||
}
|
||||
|
||||
constexpr vk::ImageViewType ToVKImageViewType(TextureType type) {
|
||||
switch (type) {
|
||||
case TextureType::kTexture2D:
|
||||
case TextureType::kTexture2DMultisample:
|
||||
return vk::ImageViewType::e2D;
|
||||
case TextureType::kTextureCube:
|
||||
return vk::ImageViewType::eCube;
|
||||
}
|
||||
FML_UNREACHABLE();
|
||||
}
|
||||
|
||||
constexpr vk::ImageCreateFlags ToVKImageCreateFlags(TextureType type) {
|
||||
switch (type) {
|
||||
case TextureType::kTexture2D:
|
||||
case TextureType::kTexture2DMultisample:
|
||||
return {};
|
||||
case TextureType::kTextureCube:
|
||||
return vk::ImageCreateFlagBits::eCubeCompatible;
|
||||
}
|
||||
FML_UNREACHABLE();
|
||||
}
|
||||
|
||||
vk::PipelineDepthStencilStateCreateInfo ToVKPipelineDepthStencilStateCreateInfo(
|
||||
std::optional<DepthAttachmentDescriptor> depth,
|
||||
std::optional<StencilAttachmentDescriptor> front,
|
||||
std::optional<StencilAttachmentDescriptor> back);
|
||||
|
||||
constexpr vk::ImageAspectFlags ToImageAspectFlags(vk::ImageLayout layout) {
|
||||
switch (layout) {
|
||||
case vk::ImageLayout::eColorAttachmentOptimal:
|
||||
case vk::ImageLayout::eShaderReadOnlyOptimal:
|
||||
case vk::ImageLayout::eTransferSrcOptimal:
|
||||
case vk::ImageLayout::eTransferDstOptimal:
|
||||
case vk::ImageLayout::ePresentSrcKHR:
|
||||
return vk::ImageAspectFlagBits::eColor;
|
||||
case vk::ImageLayout::eDepthAttachmentOptimal:
|
||||
return vk::ImageAspectFlagBits::eDepth;
|
||||
case vk::ImageLayout::eStencilAttachmentOptimal:
|
||||
return vk::ImageAspectFlagBits::eStencil;
|
||||
default:
|
||||
FML_DLOG(INFO) << "Unknown layout to determine aspect: "
|
||||
<< vk::to_string(layout);
|
||||
return vk::ImageAspectFlagBits::eNone;
|
||||
}
|
||||
FML_UNREACHABLE();
|
||||
}
|
||||
|
||||
struct LayoutTransition {
|
||||
vk::CommandBuffer cmd_buffer = {};
|
||||
vk::ImageLayout new_layout = vk::ImageLayout::eUndefined;
|
||||
vk::PipelineStageFlags src_stage = vk::PipelineStageFlagBits::eNone;
|
||||
vk::AccessFlags src_access = vk::AccessFlagBits::eNone;
|
||||
vk::PipelineStageFlags dst_stage = vk::PipelineStageFlagBits::eNone;
|
||||
vk::AccessFlags dst_access = vk::AccessFlagBits::eNone;
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@@ -53,54 +53,6 @@ bool PipelineLibraryVK::IsValid() const {
|
||||
return is_valid_;
|
||||
}
|
||||
|
||||
// |PipelineLibrary|
|
||||
PipelineFuture<PipelineDescriptor> PipelineLibraryVK::GetPipeline(
|
||||
PipelineDescriptor descriptor) {
|
||||
Lock lock(pipelines_mutex_);
|
||||
if (auto found = pipelines_.find(descriptor); found != pipelines_.end()) {
|
||||
return found->second;
|
||||
}
|
||||
|
||||
if (!IsValid()) {
|
||||
return {
|
||||
descriptor,
|
||||
RealizedFuture<std::shared_ptr<Pipeline<PipelineDescriptor>>>(nullptr)};
|
||||
}
|
||||
|
||||
auto promise = std::make_shared<
|
||||
std::promise<std::shared_ptr<Pipeline<PipelineDescriptor>>>>();
|
||||
auto pipeline_future =
|
||||
PipelineFuture<PipelineDescriptor>{descriptor, promise->get_future()};
|
||||
pipelines_[descriptor] = pipeline_future;
|
||||
|
||||
auto weak_this = weak_from_this();
|
||||
|
||||
worker_task_runner_->PostTask([descriptor, weak_this, promise]() {
|
||||
auto thiz = weak_this.lock();
|
||||
if (!thiz) {
|
||||
promise->set_value(nullptr);
|
||||
VALIDATION_LOG << "Pipeline library was collected before the pipeline "
|
||||
"could be created.";
|
||||
return;
|
||||
}
|
||||
auto pipeline_create_info =
|
||||
PipelineLibraryVK::Cast(thiz.get())->CreatePipeline(descriptor);
|
||||
promise->set_value(std::make_shared<PipelineVK>(
|
||||
weak_this, descriptor, std::move(pipeline_create_info)));
|
||||
});
|
||||
|
||||
return pipeline_future;
|
||||
}
|
||||
|
||||
// |PipelineLibrary|
|
||||
PipelineFuture<ComputePipelineDescriptor> PipelineLibraryVK::GetPipeline(
|
||||
ComputePipelineDescriptor descriptor) {
|
||||
auto promise = std::make_shared<
|
||||
std::promise<std::shared_ptr<Pipeline<ComputePipelineDescriptor>>>>();
|
||||
promise->set_value(nullptr);
|
||||
return {descriptor, promise->get_future()};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @brief Creates an attachment description that does just enough to
|
||||
/// ensure render pass compatibility with the pass associated later
|
||||
@@ -123,17 +75,6 @@ static vk::AttachmentDescription CreatePlaceholderAttachmentDescription(
|
||||
);
|
||||
}
|
||||
|
||||
// |PipelineLibrary|
|
||||
void PipelineLibraryVK::RemovePipelinesWithEntryPoint(
|
||||
std::shared_ptr<const ShaderFunction> function) {
|
||||
Lock lock(pipelines_mutex_);
|
||||
|
||||
fml::erase_if(pipelines_, [&](auto item) {
|
||||
return item->first.GetEntrypointForStage(function->GetStage())
|
||||
->IsEqual(*function);
|
||||
});
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// Render Pass
|
||||
/// We are NOT going to use the same render pass with the framebuffer (later)
|
||||
@@ -145,8 +86,8 @@ void PipelineLibraryVK::RemovePipelinesWithEntryPoint(
|
||||
/// StencilAttachmentDescriptor, and, DepthAttachmentDescriptor.
|
||||
/// Right now, these are placeholders.
|
||||
///
|
||||
vk::UniqueRenderPass PipelineLibraryVK::CreateRenderPass(
|
||||
const PipelineDescriptor& desc) {
|
||||
static vk::UniqueRenderPass CreateRenderPass(const vk::Device& device,
|
||||
const PipelineDescriptor& desc) {
|
||||
std::vector<vk::AttachmentDescription> attachments;
|
||||
|
||||
std::vector<vk::AttachmentReference> color_refs;
|
||||
@@ -190,7 +131,7 @@ vk::UniqueRenderPass PipelineLibraryVK::CreateRenderPass(
|
||||
render_pass_desc.setPSubpasses(&subpass_desc);
|
||||
render_pass_desc.setSubpassCount(1u);
|
||||
|
||||
auto [result, pass] = device_.createRenderPassUnique(render_pass_desc);
|
||||
auto [result, pass] = device.createRenderPassUnique(render_pass_desc);
|
||||
if (result != vk::Result::eSuccess) {
|
||||
VALIDATION_LOG << "Failed to create render pass for pipeline '"
|
||||
<< desc.GetLabel() << "'. Error: " << vk::to_string(result);
|
||||
@@ -210,7 +151,7 @@ constexpr vk::FrontFace ToVKFrontFace(WindingOrder order) {
|
||||
FML_UNREACHABLE();
|
||||
}
|
||||
|
||||
std::unique_ptr<PipelineCreateInfoVK> PipelineLibraryVK::CreatePipeline(
|
||||
std::unique_ptr<PipelineVK> PipelineLibraryVK::CreatePipeline(
|
||||
const PipelineDescriptor& desc) {
|
||||
TRACE_EVENT0("flutter", __FUNCTION__);
|
||||
vk::GraphicsPipelineCreateInfo pipeline_info;
|
||||
@@ -298,7 +239,7 @@ std::unique_ptr<PipelineCreateInfoVK> PipelineLibraryVK::CreatePipeline(
|
||||
blend_state.setAttachments(attachment_blend_state);
|
||||
pipeline_info.setPColorBlendState(&blend_state);
|
||||
|
||||
auto render_pass = CreateRenderPass(desc);
|
||||
auto render_pass = CreateRenderPass(device_, desc);
|
||||
if (render_pass) {
|
||||
pipeline_info.setBasePipelineHandle(VK_NULL_HANDLE);
|
||||
pipeline_info.setSubpass(0);
|
||||
@@ -341,33 +282,31 @@ std::unique_ptr<PipelineCreateInfoVK> PipelineLibraryVK::CreatePipeline(
|
||||
//----------------------------------------------------------------------------
|
||||
/// Pipeline Layout a.k.a the descriptor sets and uniforms.
|
||||
///
|
||||
std::vector<vk::DescriptorSetLayoutBinding> bindings = {};
|
||||
std::vector<vk::DescriptorSetLayoutBinding> desc_bindings;
|
||||
|
||||
for (auto layout : desc.GetVertexDescriptor()->GetDescriptorSetLayouts()) {
|
||||
auto vk_desc_layout = ToVKDescriptorSetLayoutBinding(layout);
|
||||
bindings.push_back(vk_desc_layout);
|
||||
desc_bindings.push_back(vk_desc_layout);
|
||||
}
|
||||
|
||||
vk::DescriptorSetLayoutCreateInfo descriptor_set_create;
|
||||
descriptor_set_create.setBindings(bindings);
|
||||
vk::DescriptorSetLayoutCreateInfo descs_layout_info;
|
||||
descs_layout_info.setBindings(desc_bindings);
|
||||
|
||||
auto descriptor_set_create_res =
|
||||
device_.createDescriptorSetLayoutUnique(descriptor_set_create);
|
||||
if (descriptor_set_create_res.result != vk::Result::eSuccess) {
|
||||
auto [descs_result, descs_layout] =
|
||||
device_.createDescriptorSetLayoutUnique(descs_layout_info);
|
||||
if (descs_result != vk::Result::eSuccess) {
|
||||
VALIDATION_LOG << "unable to create uniform descriptors";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
vk::UniqueDescriptorSetLayout descriptor_set_layout =
|
||||
std::move(descriptor_set_create_res.value);
|
||||
ContextVK::SetDebugName(device_, descriptor_set_layout.get(),
|
||||
"Descriptor Set Layout" + desc.GetLabel());
|
||||
ContextVK::SetDebugName(device_, descs_layout.get(),
|
||||
"Descriptor Set Layout " + desc.GetLabel());
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// Create the pipeline layout.
|
||||
///
|
||||
vk::PipelineLayoutCreateInfo pipeline_layout_info;
|
||||
pipeline_layout_info.setSetLayouts(descriptor_set_layout.get());
|
||||
pipeline_layout_info.setSetLayouts(descs_layout.get());
|
||||
auto pipeline_layout =
|
||||
device_.createPipelineLayoutUnique(pipeline_layout_info);
|
||||
if (pipeline_layout.result != vk::Result::eSuccess) {
|
||||
@@ -402,13 +341,81 @@ std::unique_ptr<PipelineCreateInfoVK> PipelineLibraryVK::CreatePipeline(
|
||||
}
|
||||
|
||||
ContextVK::SetDebugName(device_, *pipeline_layout.value,
|
||||
"Pipeline Layout" + desc.GetLabel());
|
||||
"Pipeline Layout " + desc.GetLabel());
|
||||
ContextVK::SetDebugName(device_, *pipeline.value,
|
||||
"Pipeline" + desc.GetLabel());
|
||||
"Pipeline " + desc.GetLabel());
|
||||
|
||||
return std::make_unique<PipelineCreateInfoVK>(
|
||||
std::move(pipeline.value), std::move(render_pass),
|
||||
std::move(pipeline_layout.value), std::move(descriptor_set_layout));
|
||||
return std::make_unique<PipelineVK>(weak_from_this(), //
|
||||
desc, //
|
||||
std::move(pipeline.value), //
|
||||
std::move(render_pass), //
|
||||
std::move(pipeline_layout.value), //
|
||||
std::move(descs_layout) //
|
||||
);
|
||||
}
|
||||
|
||||
// |PipelineLibrary|
|
||||
PipelineFuture<PipelineDescriptor> PipelineLibraryVK::GetPipeline(
|
||||
PipelineDescriptor descriptor) {
|
||||
Lock lock(pipelines_mutex_);
|
||||
if (auto found = pipelines_.find(descriptor); found != pipelines_.end()) {
|
||||
return found->second;
|
||||
}
|
||||
|
||||
if (!IsValid()) {
|
||||
return {
|
||||
descriptor,
|
||||
RealizedFuture<std::shared_ptr<Pipeline<PipelineDescriptor>>>(nullptr)};
|
||||
}
|
||||
|
||||
auto promise = std::make_shared<
|
||||
std::promise<std::shared_ptr<Pipeline<PipelineDescriptor>>>>();
|
||||
auto pipeline_future =
|
||||
PipelineFuture<PipelineDescriptor>{descriptor, promise->get_future()};
|
||||
pipelines_[descriptor] = pipeline_future;
|
||||
|
||||
auto weak_this = weak_from_this();
|
||||
|
||||
worker_task_runner_->PostTask([descriptor, weak_this, promise]() {
|
||||
auto thiz = weak_this.lock();
|
||||
if (!thiz) {
|
||||
promise->set_value(nullptr);
|
||||
VALIDATION_LOG << "Pipeline library was collected before the pipeline "
|
||||
"could be created.";
|
||||
return;
|
||||
}
|
||||
|
||||
auto pipeline = PipelineLibraryVK::Cast(*thiz).CreatePipeline(descriptor);
|
||||
if (!pipeline) {
|
||||
promise->set_value(nullptr);
|
||||
VALIDATION_LOG << "Could not create pipeline: " << descriptor.GetLabel();
|
||||
return;
|
||||
}
|
||||
|
||||
promise->set_value(std::move(pipeline));
|
||||
});
|
||||
|
||||
return pipeline_future;
|
||||
}
|
||||
|
||||
// |PipelineLibrary|
|
||||
PipelineFuture<ComputePipelineDescriptor> PipelineLibraryVK::GetPipeline(
|
||||
ComputePipelineDescriptor descriptor) {
|
||||
auto promise = std::make_shared<
|
||||
std::promise<std::shared_ptr<Pipeline<ComputePipelineDescriptor>>>>();
|
||||
promise->set_value(nullptr);
|
||||
return {descriptor, promise->get_future()};
|
||||
}
|
||||
|
||||
// |PipelineLibrary|
|
||||
void PipelineLibraryVK::RemovePipelinesWithEntryPoint(
|
||||
std::shared_ptr<const ShaderFunction> function) {
|
||||
Lock lock(pipelines_mutex_);
|
||||
|
||||
fml::erase_if(pipelines_, [&](auto item) {
|
||||
return item->first.GetEntrypointForStage(function->GetStage())
|
||||
->IsEqual(*function);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@@ -62,10 +62,7 @@ class PipelineLibraryVK final
|
||||
void RemovePipelinesWithEntryPoint(
|
||||
std::shared_ptr<const ShaderFunction> function) override;
|
||||
|
||||
std::unique_ptr<PipelineCreateInfoVK> CreatePipeline(
|
||||
const PipelineDescriptor& desc);
|
||||
|
||||
vk::UniqueRenderPass CreateRenderPass(const PipelineDescriptor& desc);
|
||||
std::unique_ptr<PipelineVK> CreatePipeline(const PipelineDescriptor& desc);
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(PipelineLibraryVK);
|
||||
};
|
||||
|
||||
@@ -6,53 +6,40 @@
|
||||
|
||||
namespace impeller {
|
||||
|
||||
PipelineCreateInfoVK::PipelineCreateInfoVK(
|
||||
vk::UniquePipeline pipeline,
|
||||
vk::UniqueRenderPass render_pass,
|
||||
vk::UniquePipelineLayout layout,
|
||||
vk::UniqueDescriptorSetLayout descriptor_set_layout)
|
||||
: pipeline_(std::move(pipeline)),
|
||||
render_pass_(std::move(render_pass)),
|
||||
pipeline_layout_(std::move(layout)),
|
||||
descriptor_set_layout_(std::move(descriptor_set_layout)) {
|
||||
is_valid_ =
|
||||
pipeline_ && render_pass_ && pipeline_layout_ && descriptor_set_layout_;
|
||||
}
|
||||
|
||||
bool PipelineCreateInfoVK::IsValid() const {
|
||||
return is_valid_;
|
||||
}
|
||||
|
||||
const vk::Pipeline& PipelineCreateInfoVK::GetVKPipeline() const {
|
||||
return *pipeline_;
|
||||
}
|
||||
|
||||
vk::RenderPass PipelineCreateInfoVK::GetRenderPass() const {
|
||||
return *render_pass_;
|
||||
}
|
||||
|
||||
vk::PipelineLayout PipelineCreateInfoVK::GetPipelineLayout() const {
|
||||
return *pipeline_layout_;
|
||||
}
|
||||
|
||||
vk::DescriptorSetLayout PipelineCreateInfoVK::GetDescriptorSetLayout() const {
|
||||
return *descriptor_set_layout_;
|
||||
}
|
||||
|
||||
PipelineVK::PipelineVK(std::weak_ptr<PipelineLibrary> library,
|
||||
const PipelineDescriptor& desc,
|
||||
std::unique_ptr<PipelineCreateInfoVK> create_info)
|
||||
vk::UniquePipeline pipeline,
|
||||
vk::UniqueRenderPass render_pass,
|
||||
vk::UniquePipelineLayout layout,
|
||||
vk::UniqueDescriptorSetLayout descriptor_set_layout)
|
||||
: Pipeline(std::move(library), desc),
|
||||
pipeline_info_(std::move(create_info)) {}
|
||||
pipeline_(std::move(pipeline)),
|
||||
render_pass_(std::move(render_pass)),
|
||||
layout_(std::move(layout)),
|
||||
descriptor_set_layout_(std::move(descriptor_set_layout)) {
|
||||
is_valid_ = pipeline_ && render_pass_ && layout_ && descriptor_set_layout_;
|
||||
}
|
||||
|
||||
PipelineVK::~PipelineVK() = default;
|
||||
|
||||
bool PipelineVK::IsValid() const {
|
||||
return pipeline_info_->IsValid();
|
||||
return is_valid_;
|
||||
}
|
||||
|
||||
PipelineCreateInfoVK* PipelineVK::GetCreateInfo() const {
|
||||
return pipeline_info_.get();
|
||||
const vk::Pipeline& PipelineVK::GetPipeline() const {
|
||||
return *pipeline_;
|
||||
}
|
||||
|
||||
const vk::RenderPass& PipelineVK::GetRenderPass() const {
|
||||
return *render_pass_;
|
||||
}
|
||||
|
||||
const vk::PipelineLayout& PipelineVK::GetPipelineLayout() const {
|
||||
return *layout_;
|
||||
}
|
||||
|
||||
const vk::DescriptorSetLayout& PipelineVK::GetDescriptorSetLayout() const {
|
||||
return *descriptor_set_layout_;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@@ -13,51 +13,41 @@
|
||||
|
||||
namespace impeller {
|
||||
|
||||
class PipelineCreateInfoVK {
|
||||
public:
|
||||
PipelineCreateInfoVK(vk::UniquePipeline pipeline,
|
||||
vk::UniqueRenderPass render_pass,
|
||||
vk::UniquePipelineLayout pipeline_layout,
|
||||
vk::UniqueDescriptorSetLayout descriptor_set_layout);
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
const vk::Pipeline& GetVKPipeline() const;
|
||||
|
||||
vk::RenderPass GetRenderPass() const;
|
||||
|
||||
vk::PipelineLayout GetPipelineLayout() const;
|
||||
|
||||
vk::DescriptorSetLayout GetDescriptorSetLayout() const;
|
||||
|
||||
private:
|
||||
bool is_valid_ = false;
|
||||
vk::UniquePipeline pipeline_;
|
||||
vk::UniqueRenderPass render_pass_;
|
||||
vk::UniquePipelineLayout pipeline_layout_;
|
||||
vk::UniqueDescriptorSetLayout descriptor_set_layout_;
|
||||
};
|
||||
|
||||
class PipelineVK final
|
||||
: public Pipeline<PipelineDescriptor>,
|
||||
public BackendCast<PipelineVK, Pipeline<PipelineDescriptor>> {
|
||||
public:
|
||||
PipelineVK(std::weak_ptr<PipelineLibrary> library,
|
||||
const PipelineDescriptor& desc,
|
||||
std::unique_ptr<PipelineCreateInfoVK> create_info);
|
||||
vk::UniquePipeline pipeline,
|
||||
vk::UniqueRenderPass render_pass,
|
||||
vk::UniquePipelineLayout layout,
|
||||
vk::UniqueDescriptorSetLayout descriptor_set_layout);
|
||||
|
||||
// |Pipeline|
|
||||
~PipelineVK() override;
|
||||
|
||||
PipelineCreateInfoVK* GetCreateInfo() const;
|
||||
const vk::Pipeline& GetPipeline() const;
|
||||
|
||||
const vk::RenderPass& GetRenderPass() const;
|
||||
|
||||
const vk::PipelineLayout& GetPipelineLayout() const;
|
||||
|
||||
const vk::DescriptorSetLayout& GetDescriptorSetLayout() const;
|
||||
|
||||
private:
|
||||
friend class PipelineLibraryVK;
|
||||
|
||||
const vk::UniquePipeline pipeline_;
|
||||
const vk::UniqueRenderPass render_pass_;
|
||||
const vk::UniquePipelineLayout layout_;
|
||||
const vk::UniqueDescriptorSetLayout descriptor_set_layout_;
|
||||
bool is_valid_ = false;
|
||||
|
||||
// |Pipeline|
|
||||
bool IsValid() const override;
|
||||
|
||||
std::unique_ptr<PipelineCreateInfoVK> pipeline_info_;
|
||||
std::unique_ptr<PipelineVK> CreatePipeline(const PipelineDescriptor& desc);
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(PipelineVK);
|
||||
};
|
||||
|
||||
@@ -6,9 +6,11 @@
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "fml/logging.h"
|
||||
#include "flutter/fml/logging.h"
|
||||
#include "flutter/fml/trace_event.h"
|
||||
#include "impeller/base/validation.h"
|
||||
#include "impeller/renderer/backend/vulkan/command_encoder_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/context_vk.h"
|
||||
@@ -40,8 +42,9 @@ static vk::AttachmentDescription CreateAttachmentDescription(
|
||||
);
|
||||
}
|
||||
|
||||
static vk::UniqueRenderPass CreateVKRenderPass(const vk::Device& device,
|
||||
const RenderTarget& target) {
|
||||
static SharedHandleVK<vk::RenderPass> CreateVKRenderPass(
|
||||
const vk::Device& device,
|
||||
const RenderTarget& target) {
|
||||
std::vector<vk::AttachmentDescription> attachments;
|
||||
|
||||
std::vector<vk::AttachmentReference> color_refs;
|
||||
@@ -108,7 +111,7 @@ static vk::UniqueRenderPass CreateVKRenderPass(const vk::Device& device,
|
||||
return {};
|
||||
}
|
||||
|
||||
return std::move(pass);
|
||||
return MakeSharedVK(std::move(pass));
|
||||
}
|
||||
|
||||
RenderPassVK::RenderPassVK(const std::shared_ptr<const Context>& context,
|
||||
@@ -135,7 +138,7 @@ void RenderPassVK::OnSetLabel(std::string label) {
|
||||
if (!context) {
|
||||
return;
|
||||
}
|
||||
ContextVK::Cast(*context).SetDebugName(*render_pass_, label.c_str());
|
||||
ContextVK::Cast(*context).SetDebugName(render_pass_->Get(), label.c_str());
|
||||
debug_label_ = std::move(label);
|
||||
}
|
||||
|
||||
@@ -225,34 +228,60 @@ static vk::UniqueFramebuffer CreateFramebuffer(const vk::Device& device,
|
||||
return std::move(framebuffer);
|
||||
}
|
||||
|
||||
static bool ConfigureRenderTargetAttachmentLayouts(
|
||||
const RenderTarget& target,
|
||||
const vk::CommandBuffer& command_buffer) {
|
||||
static bool ConfigureAttachments(const RenderTarget& target,
|
||||
const vk::CommandBuffer& command_buffer,
|
||||
CommandEncoderVK& encoder) {
|
||||
for (const auto& [_, color] : target.GetColorAttachments()) {
|
||||
if (!TextureVK::Cast(*color.texture)
|
||||
.SetLayout(vk::ImageLayout::eColorAttachmentOptimal,
|
||||
command_buffer)) {
|
||||
const auto& color_tex = color.texture;
|
||||
const auto& color_resolve_tex = color.resolve_texture;
|
||||
|
||||
LayoutTransition color_tran;
|
||||
color_tran.cmd_buffer = command_buffer;
|
||||
color_tran.src_access = vk::AccessFlagBits::eColorAttachmentWrite |
|
||||
vk::AccessFlagBits::eShaderWrite |
|
||||
vk::AccessFlagBits::eTransferWrite;
|
||||
color_tran.src_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput |
|
||||
vk::PipelineStageFlagBits::eFragmentShader |
|
||||
vk::PipelineStageFlagBits::eTransfer;
|
||||
color_tran.dst_access = vk::AccessFlagBits::eShaderRead;
|
||||
color_tran.dst_stage = vk::PipelineStageFlagBits::eFragmentShader;
|
||||
|
||||
color_tran.new_layout = vk::ImageLayout::eColorAttachmentOptimal;
|
||||
|
||||
// Transition and track the color texture.
|
||||
if (!TextureVK::Cast(*color_tex).SetLayout(color_tran) ||
|
||||
!encoder.Track(color_tex)) {
|
||||
return false;
|
||||
}
|
||||
if (color.resolve_texture) {
|
||||
if (!TextureVK::Cast(*color.resolve_texture)
|
||||
.SetLayout(vk::ImageLayout::eColorAttachmentOptimal,
|
||||
command_buffer)) {
|
||||
|
||||
// Transition and track the resolve texture, if there is one.
|
||||
if (color_resolve_tex) {
|
||||
if (!TextureVK::Cast(*color_resolve_tex).SetLayout(color_tran) ||
|
||||
!encoder.Track(color_resolve_tex)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LayoutTransition depth_stencil_tran;
|
||||
depth_stencil_tran.cmd_buffer = command_buffer;
|
||||
depth_stencil_tran.src_access = {};
|
||||
depth_stencil_tran.src_stage = vk::PipelineStageFlagBits::eTopOfPipe;
|
||||
depth_stencil_tran.dst_access = vk::AccessFlagBits::eShaderRead;
|
||||
depth_stencil_tran.dst_stage = vk::PipelineStageFlagBits::eFragmentShader;
|
||||
|
||||
depth_stencil_tran.new_layout = vk::ImageLayout::eDepthAttachmentOptimal;
|
||||
if (auto depth = target.GetDepthAttachment(); depth.has_value()) {
|
||||
if (!TextureVK::Cast(*depth->texture)
|
||||
.SetLayout(vk::ImageLayout::eDepthAttachmentOptimal,
|
||||
command_buffer)) {
|
||||
if (!TextureVK::Cast(*depth->texture).SetLayout(depth_stencil_tran) ||
|
||||
!encoder.Track(depth->texture)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
depth_stencil_tran.new_layout = vk::ImageLayout::eStencilAttachmentOptimal;
|
||||
if (auto stencil = target.GetStencilAttachment(); stencil.has_value()) {
|
||||
if (!TextureVK::Cast(*stencil->texture)
|
||||
.SetLayout(vk::ImageLayout::eStencilAttachmentOptimal,
|
||||
command_buffer)) {
|
||||
if (!TextureVK::Cast(*stencil->texture).SetLayout(depth_stencil_tran) ||
|
||||
!encoder.Track(stencil->texture)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -261,9 +290,19 @@ static bool ConfigureRenderTargetAttachmentLayouts(
|
||||
|
||||
static bool UpdateBindingLayouts(const Bindings& bindings,
|
||||
const vk::CommandBuffer& buffer) {
|
||||
LayoutTransition transition;
|
||||
transition.cmd_buffer = buffer;
|
||||
transition.src_access = vk::AccessFlagBits::eColorAttachmentWrite |
|
||||
vk::AccessFlagBits::eTransferWrite;
|
||||
transition.src_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput |
|
||||
vk::PipelineStageFlagBits::eTransfer;
|
||||
transition.dst_access = vk::AccessFlagBits::eShaderRead;
|
||||
transition.dst_stage = vk::PipelineStageFlagBits::eFragmentShader;
|
||||
|
||||
transition.new_layout = vk::ImageLayout::eShaderReadOnlyOptimal;
|
||||
|
||||
for (const auto& [_, texture] : bindings.textures) {
|
||||
if (!TextureVK::Cast(*texture.resource)
|
||||
.SetLayout(vk::ImageLayout::eShaderReadOnlyOptimal, buffer)) {
|
||||
if (!TextureVK::Cast(*texture.resource).SetLayout(transition)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -286,160 +325,124 @@ static bool UpdateBindingLayouts(const std::vector<Command>& commands,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool UpdateDescriptorSets(vk::Device device,
|
||||
const Bindings& bindings,
|
||||
Allocator& allocator,
|
||||
vk::DescriptorSet desc_set,
|
||||
CommandEncoderVK& encoder) {
|
||||
static bool AllocateAndBindDescriptorSets(const ContextVK& context,
|
||||
const Command& command,
|
||||
CommandEncoderVK& encoder,
|
||||
const PipelineVK& pipeline) {
|
||||
auto desc_set =
|
||||
encoder.AllocateDescriptorSet(pipeline.GetDescriptorSetLayout());
|
||||
if (!desc_set) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& allocator = *context.GetResourceAllocator();
|
||||
|
||||
std::unordered_map<uint32_t, vk::DescriptorBufferInfo> buffers;
|
||||
std::unordered_map<uint32_t, vk::DescriptorImageInfo> images;
|
||||
std::vector<vk::WriteDescriptorSet> writes;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// Setup buffer descriptors.
|
||||
///
|
||||
std::vector<vk::DescriptorBufferInfo> buffer_desc;
|
||||
for (const auto& [buffer_index, view] : bindings.buffers) {
|
||||
const auto& buffer_view = view.resource.buffer;
|
||||
auto bind_images = [&encoder, //
|
||||
&images, //
|
||||
&writes, //
|
||||
&desc_set //
|
||||
](const Bindings& bindings) -> bool {
|
||||
for (const auto& [index, sampler_handle] : bindings.samplers) {
|
||||
if (bindings.textures.find(index) == bindings.textures.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto device_buffer = buffer_view->GetDeviceBuffer(allocator);
|
||||
if (!device_buffer) {
|
||||
VALIDATION_LOG << "Failed to get device buffer for vertex binding";
|
||||
return false;
|
||||
auto texture = bindings.textures.at(index).resource;
|
||||
const auto& texture_vk = TextureVK::Cast(*texture);
|
||||
const SamplerVK& sampler = SamplerVK::Cast(*sampler_handle.resource);
|
||||
|
||||
if (!encoder.Track(texture) ||
|
||||
!encoder.Track(sampler.GetSharedSampler())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const SampledImageSlot& slot = bindings.sampled_images.at(index);
|
||||
|
||||
vk::DescriptorImageInfo image_info;
|
||||
image_info.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
|
||||
image_info.sampler = sampler.GetSampler();
|
||||
image_info.imageView = texture_vk.GetImageView();
|
||||
|
||||
vk::WriteDescriptorSet write_set;
|
||||
write_set.dstSet = desc_set.value();
|
||||
write_set.dstBinding = slot.binding;
|
||||
write_set.descriptorCount = 1u;
|
||||
write_set.descriptorType = vk::DescriptorType::eCombinedImageSampler;
|
||||
write_set.pImageInfo = &(images[slot.binding] = image_info);
|
||||
|
||||
writes.push_back(write_set);
|
||||
}
|
||||
|
||||
auto buffer = DeviceBufferVK::Cast(*device_buffer).GetVKBufferHandle();
|
||||
if (!buffer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reserved index used for per-vertex data.
|
||||
if (buffer_index == VertexDescriptor::kReservedVertexBufferIndex) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!encoder.Track(device_buffer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t offset = view.resource.range.offset;
|
||||
|
||||
vk::DescriptorBufferInfo desc_buffer_info;
|
||||
desc_buffer_info.setBuffer(buffer);
|
||||
desc_buffer_info.setOffset(offset);
|
||||
desc_buffer_info.setRange(view.resource.range.length);
|
||||
buffer_desc.push_back(desc_buffer_info);
|
||||
|
||||
const ShaderUniformSlot& uniform = bindings.uniforms.at(buffer_index);
|
||||
|
||||
vk::WriteDescriptorSet write_set;
|
||||
write_set.setDstSet(desc_set);
|
||||
write_set.setDstBinding(uniform.binding);
|
||||
write_set.setDescriptorCount(1);
|
||||
write_set.setDescriptorType(vk::DescriptorType::eUniformBuffer);
|
||||
write_set.setPBufferInfo(&buffer_desc.back());
|
||||
|
||||
writes.push_back(write_set);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// Setup image descriptors.
|
||||
///
|
||||
std::vector<vk::DescriptorImageInfo> image_descs;
|
||||
for (const auto& [index, sampler_handle] : bindings.samplers) {
|
||||
if (bindings.textures.find(index) == bindings.textures.end()) {
|
||||
VALIDATION_LOG << "Missing texture for sampler: " << index;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto texture = bindings.textures.at(index).resource;
|
||||
const auto& texture_vk = TextureVK::Cast(*texture);
|
||||
const SamplerVK& sampler = SamplerVK::Cast(*sampler_handle.resource);
|
||||
|
||||
if (!encoder.Track(texture) || !encoder.Track(sampler.GetSharedSampler())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const SampledImageSlot& slot = bindings.sampled_images.at(index);
|
||||
|
||||
vk::DescriptorImageInfo desc_image_info;
|
||||
desc_image_info.setImageLayout(vk::ImageLayout::eShaderReadOnlyOptimal);
|
||||
desc_image_info.setSampler(sampler.GetSamplerVK());
|
||||
desc_image_info.setImageView(texture_vk.GetImageView());
|
||||
image_descs.push_back(desc_image_info);
|
||||
|
||||
vk::WriteDescriptorSet write_set;
|
||||
write_set.setDstSet(desc_set);
|
||||
write_set.setDstBinding(slot.binding);
|
||||
write_set.setDescriptorCount(1);
|
||||
write_set.setDescriptorType(vk::DescriptorType::eCombinedImageSampler);
|
||||
write_set.setPImageInfo(&image_descs.back());
|
||||
|
||||
writes.push_back(write_set);
|
||||
}
|
||||
|
||||
if (writes.empty()) {
|
||||
return true;
|
||||
}
|
||||
device.updateDescriptorSets(writes, {});
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool AllocateAndBindDescriptorSets(
|
||||
const ContextVK& context,
|
||||
const Command& command,
|
||||
CommandEncoderVK& encoder,
|
||||
PipelineCreateInfoVK* pipeline_create_info) {
|
||||
auto& allocator = *context.GetResourceAllocator();
|
||||
vk::PipelineLayout pipeline_layout =
|
||||
pipeline_create_info->GetPipelineLayout();
|
||||
|
||||
vk::DescriptorSetAllocateInfo alloc_info;
|
||||
std::array<vk::DescriptorSetLayout, 1> dsls = {
|
||||
pipeline_create_info->GetDescriptorSetLayout(),
|
||||
};
|
||||
|
||||
alloc_info.setDescriptorPool(context.GetDescriptorPool());
|
||||
alloc_info.setSetLayouts(dsls);
|
||||
auto bind_buffers = [&allocator, //
|
||||
&encoder, //
|
||||
&buffers, //
|
||||
&writes, //
|
||||
&desc_set //
|
||||
](const Bindings& bindings) -> bool {
|
||||
for (const auto& [buffer_index, view] : bindings.buffers) {
|
||||
const auto& buffer_view = view.resource.buffer;
|
||||
|
||||
auto [sets_result, sets] =
|
||||
context.GetDevice().allocateDescriptorSetsUnique(alloc_info);
|
||||
if (sets_result != vk::Result::eSuccess) {
|
||||
VALIDATION_LOG << "Failed to allocate descriptor sets: "
|
||||
<< vk::to_string(sets_result);
|
||||
auto device_buffer = buffer_view->GetDeviceBuffer(allocator);
|
||||
if (!device_buffer) {
|
||||
VALIDATION_LOG << "Failed to get device buffer for vertex binding";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto buffer = DeviceBufferVK::Cast(*device_buffer).GetBuffer();
|
||||
if (!buffer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reserved index used for per-vertex data.
|
||||
if (buffer_index == VertexDescriptor::kReservedVertexBufferIndex) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!encoder.Track(device_buffer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t offset = view.resource.range.offset;
|
||||
|
||||
vk::DescriptorBufferInfo buffer_info;
|
||||
buffer_info.buffer = buffer;
|
||||
buffer_info.offset = offset;
|
||||
buffer_info.range = view.resource.range.length;
|
||||
|
||||
const ShaderUniformSlot& uniform = bindings.uniforms.at(buffer_index);
|
||||
|
||||
vk::WriteDescriptorSet write_set;
|
||||
write_set.dstSet = desc_set.value();
|
||||
write_set.dstBinding = uniform.binding;
|
||||
write_set.descriptorCount = 1u;
|
||||
write_set.descriptorType = vk::DescriptorType::eUniformBuffer;
|
||||
write_set.pBufferInfo = &(buffers[uniform.binding] = buffer_info);
|
||||
|
||||
writes.push_back(write_set);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!bind_buffers(command.vertex_bindings) ||
|
||||
!bind_buffers(command.fragment_bindings) ||
|
||||
!bind_images(command.fragment_bindings)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto set = MakeSharedVK<vk::DescriptorSet>(std::move(sets[0]));
|
||||
|
||||
if (!encoder.Track(set)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool update_vertex_descriptors =
|
||||
UpdateDescriptorSets(context.GetDevice(), //
|
||||
command.vertex_bindings, //
|
||||
allocator, //
|
||||
*set, //
|
||||
encoder //
|
||||
);
|
||||
if (!update_vertex_descriptors) {
|
||||
return false;
|
||||
}
|
||||
bool update_frag_descriptors =
|
||||
UpdateDescriptorSets(context.GetDevice(), //
|
||||
command.fragment_bindings, //
|
||||
allocator, //
|
||||
*set, //
|
||||
encoder //
|
||||
);
|
||||
if (!update_frag_descriptors) {
|
||||
return false;
|
||||
}
|
||||
context.GetDevice().updateDescriptorSets(writes, {});
|
||||
|
||||
encoder.GetCommandBuffer().bindDescriptorSets(
|
||||
vk::PipelineBindPoint::eGraphics, // bind point
|
||||
pipeline_layout, // layout
|
||||
pipeline.GetPipelineLayout(), // layout
|
||||
0, // first set
|
||||
{vk::DescriptorSet{*set}}, // sets
|
||||
{vk::DescriptorSet{*desc_set}}, // sets
|
||||
nullptr // offsets
|
||||
);
|
||||
return true;
|
||||
@@ -486,19 +489,18 @@ static bool EncodeCommand(const Context& context,
|
||||
|
||||
const auto& cmd_buffer = encoder.GetCommandBuffer();
|
||||
|
||||
auto& pipeline_vk = PipelineVK::Cast(*command.pipeline);
|
||||
PipelineCreateInfoVK* pipeline_create_info = pipeline_vk.GetCreateInfo();
|
||||
const auto& pipeline_vk = PipelineVK::Cast(*command.pipeline);
|
||||
|
||||
if (!AllocateAndBindDescriptorSets(ContextVK::Cast(context), //
|
||||
command, //
|
||||
encoder, //
|
||||
pipeline_create_info //
|
||||
pipeline_vk //
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cmd_buffer.bindPipeline(vk::PipelineBindPoint::eGraphics,
|
||||
pipeline_create_info->GetVKPipeline());
|
||||
pipeline_vk.GetPipeline());
|
||||
|
||||
// Set the viewport and scissors.
|
||||
SetViewportAndScissor(command, cmd_buffer, target_size);
|
||||
@@ -532,15 +534,13 @@ static bool EncodeCommand(const Context& context,
|
||||
}
|
||||
|
||||
// Bind the vertex buffer.
|
||||
auto vertex_buffer_handle =
|
||||
DeviceBufferVK::Cast(*vertex_buffer).GetVKBufferHandle();
|
||||
auto vertex_buffer_handle = DeviceBufferVK::Cast(*vertex_buffer).GetBuffer();
|
||||
vk::Buffer vertex_buffers[] = {vertex_buffer_handle};
|
||||
vk::DeviceSize vertex_buffer_offsets[] = {vertex_buffer_view.range.offset};
|
||||
cmd_buffer.bindVertexBuffers(0u, 1u, vertex_buffers, vertex_buffer_offsets);
|
||||
|
||||
// Bind the index buffer.
|
||||
auto index_buffer_handle =
|
||||
DeviceBufferVK::Cast(*index_buffer).GetVKBufferHandle();
|
||||
auto index_buffer_handle = DeviceBufferVK::Cast(*index_buffer).GetBuffer();
|
||||
cmd_buffer.bindIndexBuffer(index_buffer_handle,
|
||||
index_buffer_view.range.offset,
|
||||
ToVKIndexType(command.index_type));
|
||||
@@ -556,14 +556,11 @@ static bool EncodeCommand(const Context& context,
|
||||
}
|
||||
|
||||
bool RenderPassVK::OnEncodeCommands(const Context& context) const {
|
||||
TRACE_EVENT0("impeller", "RenderPassVK::OnEncodeCommands");
|
||||
if (!IsValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (commands_.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto& vk_context = ContextVK::Cast(context);
|
||||
|
||||
const auto& render_target = GetRenderTarget();
|
||||
@@ -593,16 +590,23 @@ bool RenderPassVK::OnEncodeCommands(const Context& context) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ConfigureRenderTargetAttachmentLayouts(render_target, cmd_buffer)) {
|
||||
if (!ConfigureAttachments(render_target, cmd_buffer, *encoder)) {
|
||||
VALIDATION_LOG << "Could not complete attachment layout transitions.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (commands_.empty()) {
|
||||
// All the necessary layout transitions of the attchments have been
|
||||
// completed by this point. If there are no commands, there is nothing
|
||||
// further to do.
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto& target_size = render_target.GetRenderTargetSize();
|
||||
|
||||
auto framebuffer = MakeSharedVK(
|
||||
CreateFramebuffer(vk_context.GetDevice(), render_target_, *render_pass_));
|
||||
if (!encoder->Track(framebuffer)) {
|
||||
if (!encoder->Track(framebuffer) || !encoder->Track(render_pass_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -617,6 +621,7 @@ bool RenderPassVK::OnEncodeCommands(const Context& context) const {
|
||||
pass_info.setClearValues(clear_values);
|
||||
|
||||
{
|
||||
TRACE_EVENT0("impeller", "EncodeRenderPassCommands");
|
||||
cmd_buffer.beginRenderPass(pass_info, vk::SubpassContents::eInline);
|
||||
|
||||
fml::ScopedCleanupClosure end_render_pass(
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/renderer/backend/vulkan/context_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/shared_object_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/texture_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/vk.h"
|
||||
#include "impeller/renderer/command.h"
|
||||
@@ -22,7 +23,7 @@ class RenderPassVK final : public RenderPass {
|
||||
private:
|
||||
friend class CommandBufferVK;
|
||||
|
||||
vk::UniqueRenderPass render_pass_;
|
||||
SharedHandleVK<vk::RenderPass> render_pass_;
|
||||
std::weak_ptr<CommandEncoderVK> encoder_;
|
||||
std::string debug_label_;
|
||||
bool is_valid_ = false;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "impeller/renderer/backend/vulkan/sampler_library_vk.h"
|
||||
|
||||
#include "impeller/renderer/backend/vulkan/context_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/formats_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/sampler_vk.h"
|
||||
|
||||
@@ -51,6 +52,11 @@ std::shared_ptr<const Sampler> SamplerLibraryVK::GetSampler(
|
||||
if (!sampler->IsValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!desc.label.empty()) {
|
||||
ContextVK::SetDebugName(device_, sampler->GetSampler(), desc.label.c_str());
|
||||
}
|
||||
|
||||
samplers_[desc] = sampler;
|
||||
return sampler;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ SamplerVK::SamplerVK(SamplerDescriptor desc, vk::UniqueSampler sampler)
|
||||
|
||||
SamplerVK::~SamplerVK() = default;
|
||||
|
||||
vk::Sampler SamplerVK::GetSamplerVK() const {
|
||||
vk::Sampler SamplerVK::GetSampler() const {
|
||||
return *sampler_;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ class SamplerVK final : public Sampler, public BackendCast<SamplerVK, Sampler> {
|
||||
// |Sampler|
|
||||
~SamplerVK() override;
|
||||
|
||||
vk::Sampler GetSamplerVK() const;
|
||||
vk::Sampler GetSampler() const;
|
||||
|
||||
const std::shared_ptr<SharedObjectVKT<vk::Sampler>>& GetSharedSampler() const;
|
||||
|
||||
|
||||
@@ -25,10 +25,14 @@ class SharedObjectVKT : public SharedObjectVK {
|
||||
|
||||
explicit SharedObjectVKT(UniqueResource res) : resource_(std::move(res)) {}
|
||||
|
||||
operator Resource() const { return *resource_; }
|
||||
operator Resource() const { return Get(); }
|
||||
|
||||
const Resource& Get() const { return *resource_; }
|
||||
|
||||
private:
|
||||
UniqueResource resource_;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(SharedObjectVKT);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
@@ -40,4 +44,7 @@ auto MakeSharedVK(
|
||||
return std::make_shared<SharedObjectVKT<T>>(std::move(handle));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
using SharedHandleVK = std::shared_ptr<SharedObjectVKT<T>>;
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@@ -43,9 +43,8 @@ std::unique_ptr<SurfaceVK> SurfaceVK::WrapSwapchainImage(
|
||||
resolve_tex_desc.storage_mode = StorageMode::kDevicePrivate;
|
||||
|
||||
std::shared_ptr<Texture> resolve_tex =
|
||||
std::make_shared<TextureVK>(resolve_tex_desc, //
|
||||
context, //
|
||||
swapchain_image //
|
||||
std::make_shared<TextureVK>(context, //
|
||||
swapchain_image //
|
||||
);
|
||||
|
||||
if (!resolve_tex) {
|
||||
@@ -65,8 +64,7 @@ std::unique_ptr<SurfaceVK> SurfaceVK::WrapSwapchainImage(
|
||||
stencil0_tex.storage_mode = StorageMode::kDeviceTransient;
|
||||
stencil0_tex.type = TextureType::kTexture2D;
|
||||
stencil0_tex.sample_count = SampleCount::kCount4;
|
||||
stencil0_tex.format =
|
||||
context->GetDeviceCapabilities().GetDefaultStencilFormat();
|
||||
stencil0_tex.format = context->GetCapabilities()->GetDefaultStencilFormat();
|
||||
stencil0_tex.size = msaa_tex_desc.size;
|
||||
stencil0_tex.usage =
|
||||
static_cast<TextureUsageMask>(TextureUsage::kRenderTarget);
|
||||
|
||||
@@ -6,25 +6,22 @@
|
||||
|
||||
namespace impeller {
|
||||
|
||||
SwapchainImageVK::SwapchainImageVK(vk::Device device,
|
||||
vk::Image image,
|
||||
PixelFormat image_format,
|
||||
ISize image_size)
|
||||
: image_(image), image_format_(image_format), image_size_(image_size) {
|
||||
SwapchainImageVK::SwapchainImageVK(TextureDescriptor desc,
|
||||
vk::Device device,
|
||||
vk::Image image)
|
||||
: TextureSourceVK(desc), image_(image) {
|
||||
vk::ImageViewCreateInfo view_info;
|
||||
view_info.image = image_;
|
||||
view_info.viewType = vk::ImageViewType::e2D;
|
||||
view_info.format = ToVKImageFormat(image_format_);
|
||||
view_info.format = ToVKImageFormat(desc.format);
|
||||
view_info.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor;
|
||||
view_info.subresourceRange.baseMipLevel = 0u;
|
||||
view_info.subresourceRange.levelCount = 1u;
|
||||
view_info.subresourceRange.baseArrayLayer = 0u;
|
||||
view_info.subresourceRange.layerCount = 1u;
|
||||
view_info.subresourceRange.levelCount = desc.mip_count;
|
||||
view_info.subresourceRange.layerCount = ToArrayLayerCount(desc.type);
|
||||
|
||||
auto [view_result, view] = device.createImageViewUnique(view_info);
|
||||
if (view_result != vk::Result::eSuccess) {
|
||||
VALIDATION_LOG << "Could not create image view: "
|
||||
<< vk::to_string(view_result);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -39,20 +36,20 @@ bool SwapchainImageVK::IsValid() const {
|
||||
}
|
||||
|
||||
PixelFormat SwapchainImageVK::GetPixelFormat() const {
|
||||
return image_format_;
|
||||
return desc_.format;
|
||||
}
|
||||
|
||||
ISize SwapchainImageVK::GetSize() const {
|
||||
return image_size_;
|
||||
return desc_.size;
|
||||
}
|
||||
|
||||
// |TextureSourceVK|
|
||||
vk::Image SwapchainImageVK::GetVKImage() const {
|
||||
vk::Image SwapchainImageVK::GetImage() const {
|
||||
return image_;
|
||||
}
|
||||
|
||||
// |TextureSourceVK|
|
||||
vk::ImageView SwapchainImageVK::GetVKImageView() const {
|
||||
vk::ImageView SwapchainImageVK::GetImageView() const {
|
||||
return image_view_.get();
|
||||
}
|
||||
|
||||
|
||||
@@ -14,10 +14,7 @@ namespace impeller {
|
||||
|
||||
class SwapchainImageVK final : public TextureSourceVK {
|
||||
public:
|
||||
SwapchainImageVK(vk::Device device,
|
||||
vk::Image image,
|
||||
PixelFormat image_format,
|
||||
ISize image_size);
|
||||
SwapchainImageVK(TextureDescriptor desc, vk::Device device, vk::Image image);
|
||||
|
||||
// |TextureSourceVK|
|
||||
~SwapchainImageVK() override;
|
||||
@@ -29,15 +26,13 @@ class SwapchainImageVK final : public TextureSourceVK {
|
||||
ISize GetSize() const;
|
||||
|
||||
// |TextureSourceVK|
|
||||
vk::Image GetVKImage() const override;
|
||||
vk::Image GetImage() const override;
|
||||
|
||||
// |TextureSourceVK|
|
||||
vk::ImageView GetVKImageView() const override;
|
||||
vk::ImageView GetImageView() const override;
|
||||
|
||||
private:
|
||||
vk::Image image_ = VK_NULL_HANDLE;
|
||||
PixelFormat image_format_ = PixelFormat::kUnknown;
|
||||
ISize image_size_;
|
||||
vk::UniqueImageView image_view_ = {};
|
||||
bool is_valid_ = false;
|
||||
|
||||
|
||||
@@ -150,7 +150,7 @@ SwapchainImplVK::SwapchainImplVK(const std::shared_ptr<Context>& context,
|
||||
}
|
||||
|
||||
const auto format = ChooseSurfaceFormat(
|
||||
formats, vk_context.GetDeviceCapabilities().GetDefaultColorFormat());
|
||||
formats, vk_context.GetCapabilities()->GetDefaultColorFormat());
|
||||
if (!format.has_value()) {
|
||||
VALIDATION_LOG << "Swapchain has no supported formats.";
|
||||
return;
|
||||
@@ -213,19 +213,33 @@ SwapchainImplVK::SwapchainImplVK(const std::shared_ptr<Context>& context,
|
||||
return;
|
||||
}
|
||||
|
||||
TextureDescriptor texture_desc;
|
||||
texture_desc.usage =
|
||||
static_cast<decltype(texture_desc.usage)>(TextureUsage::kRenderTarget);
|
||||
texture_desc.storage_mode = StorageMode::kDevicePrivate;
|
||||
texture_desc.format = ToPixelFormat(swapchain_info.imageFormat);
|
||||
texture_desc.size = ISize::MakeWH(swapchain_info.imageExtent.width,
|
||||
swapchain_info.imageExtent.height);
|
||||
|
||||
std::vector<std::shared_ptr<SwapchainImageVK>> swapchain_images;
|
||||
for (const auto& image : images) {
|
||||
auto swapchain_image = std::make_shared<SwapchainImageVK>(
|
||||
vk_context.GetDevice(), //
|
||||
image, //
|
||||
ToPixelFormat(swapchain_info.imageFormat), //
|
||||
ISize::MakeWH(swapchain_info.imageExtent.width,
|
||||
swapchain_info.imageExtent.height) //
|
||||
);
|
||||
auto swapchain_image =
|
||||
std::make_shared<SwapchainImageVK>(texture_desc, // texture descriptor
|
||||
vk_context.GetDevice(), // device
|
||||
image // image
|
||||
);
|
||||
if (!swapchain_image->IsValid()) {
|
||||
VALIDATION_LOG << "Could not create swapchain image.";
|
||||
return;
|
||||
}
|
||||
|
||||
ContextVK::SetDebugName(
|
||||
vk_context.GetDevice(), swapchain_image->GetImage(),
|
||||
"SwapchainImage" + std::to_string(swapchain_images.size()));
|
||||
ContextVK::SetDebugName(
|
||||
vk_context.GetDevice(), swapchain_image->GetImageView(),
|
||||
"SwapchainImageView" + std::to_string(swapchain_images.size()));
|
||||
|
||||
swapchain_images.emplace_back(swapchain_image);
|
||||
}
|
||||
|
||||
@@ -366,24 +380,19 @@ bool SwapchainImplVK::Present(const std::shared_ptr<SwapchainImageVK>& image,
|
||||
|
||||
auto vk_cmd_buffer =
|
||||
CommandBufferVK::Cast(*cmd_buffer).GetEncoder()->GetCommandBuffer();
|
||||
vk::ImageMemoryBarrier image_barrier;
|
||||
image_barrier.srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite;
|
||||
image_barrier.dstAccessMask = vk::AccessFlagBits::eColorAttachmentRead;
|
||||
image_barrier.image = image->GetVKImage();
|
||||
image_barrier.oldLayout = vk::ImageLayout::eColorAttachmentOptimal;
|
||||
image_barrier.newLayout = vk::ImageLayout::ePresentSrcKHR;
|
||||
image_barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor;
|
||||
image_barrier.subresourceRange.baseMipLevel = 0u;
|
||||
image_barrier.subresourceRange.levelCount = 1u;
|
||||
image_barrier.subresourceRange.baseArrayLayer = 0u;
|
||||
image_barrier.subresourceRange.layerCount = 1u;
|
||||
vk_cmd_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eAllGraphics, //
|
||||
vk::PipelineStageFlagBits::eAllGraphics, //
|
||||
{}, //
|
||||
nullptr, //
|
||||
nullptr, //
|
||||
image_barrier //
|
||||
);
|
||||
|
||||
LayoutTransition transition;
|
||||
transition.new_layout = vk::ImageLayout::ePresentSrcKHR;
|
||||
transition.cmd_buffer = vk_cmd_buffer;
|
||||
transition.src_access = vk::AccessFlagBits::eColorAttachmentWrite;
|
||||
transition.src_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput;
|
||||
transition.dst_access = {};
|
||||
transition.dst_stage = vk::PipelineStageFlagBits::eBottomOfPipe;
|
||||
|
||||
if (!image->SetLayout(transition)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!cmd_buffer->SubmitCommands()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,59 @@
|
||||
|
||||
namespace impeller {
|
||||
|
||||
TextureSourceVK::TextureSourceVK(TextureDescriptor desc) : desc_(desc) {}
|
||||
|
||||
TextureSourceVK::~TextureSourceVK() = default;
|
||||
|
||||
const TextureDescriptor& TextureSourceVK::GetTextureDescriptor() const {
|
||||
return desc_;
|
||||
}
|
||||
|
||||
vk::ImageLayout TextureSourceVK::GetLayout() const {
|
||||
ReaderLock lock(layout_mutex_);
|
||||
return layout_;
|
||||
}
|
||||
|
||||
vk::ImageLayout TextureSourceVK::SetLayoutWithoutEncoding(
|
||||
vk::ImageLayout layout) const {
|
||||
WriterLock lock(layout_mutex_);
|
||||
const auto old_layout = layout_;
|
||||
layout_ = layout;
|
||||
return old_layout;
|
||||
}
|
||||
|
||||
bool TextureSourceVK::SetLayout(const LayoutTransition& transition) const {
|
||||
const auto old_layout = SetLayoutWithoutEncoding(transition.new_layout);
|
||||
if (transition.new_layout == old_layout) {
|
||||
return true;
|
||||
}
|
||||
|
||||
vk::ImageMemoryBarrier image_barrier;
|
||||
image_barrier.srcAccessMask = transition.src_access;
|
||||
image_barrier.dstAccessMask = transition.dst_access;
|
||||
image_barrier.oldLayout = old_layout;
|
||||
image_barrier.newLayout = transition.new_layout;
|
||||
image_barrier.image = GetImage();
|
||||
image_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
image_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
image_barrier.subresourceRange.aspectMask =
|
||||
ToImageAspectFlags(transition.new_layout);
|
||||
image_barrier.subresourceRange.baseMipLevel = 0u;
|
||||
image_barrier.subresourceRange.levelCount = desc_.mip_count;
|
||||
image_barrier.subresourceRange.baseArrayLayer = 0u;
|
||||
image_barrier.subresourceRange.layerCount = ToArrayLayerCount(desc_.type);
|
||||
|
||||
transition.cmd_buffer.pipelineBarrier(transition.src_stage, // src stage
|
||||
transition.dst_stage, // dst stage
|
||||
{}, // dependency flags
|
||||
nullptr, // memory barriers
|
||||
nullptr, // buffer barriers
|
||||
image_barrier // image barriers
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TextureSourceVK::SetContents(const TextureDescriptor& desc,
|
||||
const uint8_t* contents,
|
||||
size_t length,
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/base/thread.h"
|
||||
#include "impeller/renderer/backend/vulkan/formats_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/vk.h"
|
||||
#include "impeller/renderer/texture_descriptor.h"
|
||||
|
||||
@@ -12,16 +14,34 @@ namespace impeller {
|
||||
|
||||
class TextureSourceVK {
|
||||
public:
|
||||
virtual ~TextureSourceVK() = default;
|
||||
virtual ~TextureSourceVK();
|
||||
|
||||
const TextureDescriptor& GetTextureDescriptor() const;
|
||||
|
||||
virtual bool SetContents(const TextureDescriptor& desc,
|
||||
const uint8_t* contents,
|
||||
size_t length,
|
||||
size_t slice);
|
||||
|
||||
virtual vk::Image GetVKImage() const = 0;
|
||||
virtual vk::Image GetImage() const = 0;
|
||||
|
||||
virtual vk::ImageView GetVKImageView() const = 0;
|
||||
virtual vk::ImageView GetImageView() const = 0;
|
||||
|
||||
bool SetLayout(const LayoutTransition& transition) const;
|
||||
|
||||
vk::ImageLayout SetLayoutWithoutEncoding(vk::ImageLayout layout) const;
|
||||
|
||||
vk::ImageLayout GetLayout() const;
|
||||
|
||||
protected:
|
||||
const TextureDescriptor desc_;
|
||||
|
||||
explicit TextureSourceVK(TextureDescriptor desc);
|
||||
|
||||
private:
|
||||
mutable RWMutex layout_mutex_;
|
||||
mutable vk::ImageLayout layout_ IPLR_GUARDED_BY(layout_mutex_) =
|
||||
vk::ImageLayout::eUndefined;
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@@ -4,12 +4,17 @@
|
||||
|
||||
#include "impeller/renderer/backend/vulkan/texture_vk.h"
|
||||
|
||||
#include "impeller/renderer/backend/vulkan/command_buffer_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/command_encoder_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/formats_vk.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
TextureVK::TextureVK(TextureDescriptor desc,
|
||||
std::weak_ptr<Context> context,
|
||||
TextureVK::TextureVK(std::weak_ptr<Context> context,
|
||||
std::shared_ptr<TextureSourceVK> source)
|
||||
: Texture(desc), context_(std::move(context)), source_(std::move(source)) {}
|
||||
: Texture(source->GetTextureDescriptor()),
|
||||
context_(std::move(context)),
|
||||
source_(std::move(source)) {}
|
||||
|
||||
TextureVK::~TextureVK() = default;
|
||||
|
||||
@@ -20,6 +25,7 @@ void TextureVK::SetLabel(std::string_view label) {
|
||||
return;
|
||||
}
|
||||
ContextVK::Cast(*context).SetDebugName(GetImage(), label);
|
||||
ContextVK::Cast(*context).SetDebugName(GetImageView(), label);
|
||||
}
|
||||
|
||||
bool TextureVK::OnSetContents(const uint8_t* contents,
|
||||
@@ -33,11 +39,74 @@ bool TextureVK::OnSetContents(const uint8_t* contents,
|
||||
|
||||
// Out of bounds access.
|
||||
if (length != desc.GetByteSizeOfBaseMipLevel()) {
|
||||
VALIDATION_LOG << "illegal to set contents for invalid size";
|
||||
VALIDATION_LOG << "Illegal to set contents for invalid size.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return source_->SetContents(desc, contents, length, slice);
|
||||
auto context = context_.lock();
|
||||
if (!context) {
|
||||
VALIDATION_LOG << "Context died before setting contents on texture.";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto staging_buffer =
|
||||
context->GetResourceAllocator()->CreateBufferWithCopy(contents, length);
|
||||
|
||||
if (!staging_buffer) {
|
||||
VALIDATION_LOG << "Could not create staging buffer.";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto cmd_buffer = context->CreateCommandBuffer();
|
||||
|
||||
if (!cmd_buffer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto encoder = CommandBufferVK::Cast(*cmd_buffer).GetEncoder();
|
||||
|
||||
if (!encoder->Track(staging_buffer) || !encoder->Track(source_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& vk_cmd_buffer = encoder->GetCommandBuffer();
|
||||
|
||||
LayoutTransition transition;
|
||||
transition.cmd_buffer = vk_cmd_buffer;
|
||||
transition.new_layout = vk::ImageLayout::eTransferDstOptimal;
|
||||
transition.src_access = {};
|
||||
transition.src_stage = vk::PipelineStageFlagBits::eTopOfPipe;
|
||||
transition.dst_access = vk::AccessFlagBits::eTransferWrite;
|
||||
transition.dst_stage = vk::PipelineStageFlagBits::eTransfer;
|
||||
|
||||
if (!SetLayout(transition)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
vk::BufferImageCopy copy;
|
||||
copy.bufferOffset = 0u;
|
||||
copy.bufferRowLength = 0u; // 0u means tightly packed per spec.
|
||||
copy.bufferImageHeight = 0u; // 0u means tightly packed per spec.
|
||||
copy.imageOffset.x = 0u;
|
||||
copy.imageOffset.y = 0u;
|
||||
copy.imageOffset.z = 0u;
|
||||
copy.imageExtent.width = desc.size.width;
|
||||
copy.imageExtent.height = desc.size.height;
|
||||
copy.imageExtent.depth = 1u;
|
||||
copy.imageSubresource.aspectMask = vk::ImageAspectFlagBits::eColor;
|
||||
copy.imageSubresource.mipLevel = 0u;
|
||||
copy.imageSubresource.baseArrayLayer = slice;
|
||||
copy.imageSubresource.layerCount = 1u;
|
||||
|
||||
vk_cmd_buffer.copyBufferToImage(
|
||||
DeviceBufferVK::Cast(*staging_buffer).GetBuffer(), // src buffer
|
||||
GetImage(), // dst image
|
||||
transition.new_layout, // dst image layout
|
||||
1u, // region count
|
||||
© // regions
|
||||
);
|
||||
|
||||
return cmd_buffer->SubmitCommands();
|
||||
}
|
||||
|
||||
bool TextureVK::OnSetContents(std::shared_ptr<const fml::Mapping> mapping,
|
||||
@@ -56,75 +125,29 @@ ISize TextureVK::GetSize() const {
|
||||
}
|
||||
|
||||
vk::Image TextureVK::GetImage() const {
|
||||
return source_->GetVKImage();
|
||||
return source_->GetImage();
|
||||
}
|
||||
|
||||
vk::ImageView TextureVK::GetImageView() const {
|
||||
return source_->GetVKImageView();
|
||||
return source_->GetImageView();
|
||||
}
|
||||
|
||||
static constexpr vk::ImageAspectFlags ToImageAspectFlags(
|
||||
vk::ImageLayout layout) {
|
||||
switch (layout) {
|
||||
case vk::ImageLayout::eColorAttachmentOptimal:
|
||||
case vk::ImageLayout::eShaderReadOnlyOptimal:
|
||||
return vk::ImageAspectFlagBits::eColor;
|
||||
case vk::ImageLayout::eDepthAttachmentOptimal:
|
||||
return vk::ImageAspectFlagBits::eDepth;
|
||||
case vk::ImageLayout::eStencilAttachmentOptimal:
|
||||
return vk::ImageAspectFlagBits::eStencil;
|
||||
default:
|
||||
FML_DLOG(INFO) << "Unknown layout to determine aspect.";
|
||||
return vk::ImageAspectFlagBits::eNone;
|
||||
}
|
||||
FML_UNREACHABLE();
|
||||
std::shared_ptr<const TextureSourceVK> TextureVK::GetTextureSource() const {
|
||||
return source_;
|
||||
}
|
||||
|
||||
vk::ImageLayout TextureVK::GetLayout() const {
|
||||
ReaderLock lock(layout_mutex_);
|
||||
return layout_;
|
||||
bool TextureVK::SetLayout(const LayoutTransition& transition) const {
|
||||
return source_ ? source_->SetLayout(transition) : false;
|
||||
}
|
||||
|
||||
vk::ImageLayout TextureVK::SetLayoutWithoutEncoding(
|
||||
vk::ImageLayout layout) const {
|
||||
WriterLock lock(layout_mutex_);
|
||||
const auto old_layout = layout_;
|
||||
layout_ = layout;
|
||||
return old_layout;
|
||||
return source_ ? source_->SetLayoutWithoutEncoding(layout)
|
||||
: vk::ImageLayout::eUndefined;
|
||||
}
|
||||
|
||||
bool TextureVK::SetLayout(vk::ImageLayout new_layout,
|
||||
const vk::CommandBuffer& buffer) const {
|
||||
const auto old_layout = SetLayoutWithoutEncoding(new_layout);
|
||||
if (new_layout == old_layout) {
|
||||
return true;
|
||||
}
|
||||
|
||||
vk::ImageMemoryBarrier image_barrier;
|
||||
image_barrier.srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite |
|
||||
vk::AccessFlagBits::eTransferWrite;
|
||||
image_barrier.dstAccessMask = vk::AccessFlagBits::eColorAttachmentRead |
|
||||
vk::AccessFlagBits::eShaderRead;
|
||||
image_barrier.oldLayout = old_layout;
|
||||
image_barrier.newLayout = new_layout;
|
||||
image_barrier.image = GetImage();
|
||||
image_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
image_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
image_barrier.subresourceRange.aspectMask = ToImageAspectFlags(new_layout);
|
||||
image_barrier.subresourceRange.baseMipLevel = 0u;
|
||||
image_barrier.subresourceRange.levelCount = GetTextureDescriptor().mip_count;
|
||||
image_barrier.subresourceRange.baseArrayLayer = 0u;
|
||||
image_barrier.subresourceRange.layerCount = 1u;
|
||||
|
||||
buffer.pipelineBarrier(vk::PipelineStageFlagBits::eAllGraphics, // src stage
|
||||
vk::PipelineStageFlagBits::eAllGraphics, // dst stage
|
||||
{}, // dependency flags
|
||||
nullptr, // memory barriers
|
||||
nullptr, // buffer barriers
|
||||
image_barrier // image barriers
|
||||
);
|
||||
|
||||
return true;
|
||||
vk::ImageLayout TextureVK::GetLayout() const {
|
||||
return source_ ? source_->GetLayout() : vk::ImageLayout::eUndefined;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/base/backend_cast.h"
|
||||
#include "impeller/base/thread.h"
|
||||
#include "impeller/renderer/backend/vulkan/context_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/device_buffer_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/formats_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/texture_source_vk.h"
|
||||
#include "impeller/renderer/backend/vulkan/vk.h"
|
||||
#include "impeller/renderer/texture.h"
|
||||
@@ -19,8 +19,7 @@ namespace impeller {
|
||||
|
||||
class TextureVK final : public Texture, public BackendCast<TextureVK, Texture> {
|
||||
public:
|
||||
TextureVK(TextureDescriptor desc,
|
||||
std::weak_ptr<Context> context,
|
||||
TextureVK(std::weak_ptr<Context> context,
|
||||
std::shared_ptr<TextureSourceVK> source);
|
||||
|
||||
// |Texture|
|
||||
@@ -30,12 +29,14 @@ class TextureVK final : public Texture, public BackendCast<TextureVK, Texture> {
|
||||
|
||||
vk::ImageView GetImageView() const;
|
||||
|
||||
bool SetLayout(vk::ImageLayout layout, const vk::CommandBuffer& buffer) const;
|
||||
bool SetLayout(const LayoutTransition& transition) const;
|
||||
|
||||
vk::ImageLayout SetLayoutWithoutEncoding(vk::ImageLayout layout) const;
|
||||
|
||||
vk::ImageLayout GetLayout() const;
|
||||
|
||||
std::shared_ptr<const TextureSourceVK> GetTextureSource() const;
|
||||
|
||||
private:
|
||||
std::weak_ptr<Context> context_;
|
||||
std::shared_ptr<TextureSourceVK> source_;
|
||||
|
||||
159
engine/src/flutter/impeller/renderer/capabilities.cc
Normal file
159
engine/src/flutter/impeller/renderer/capabilities.cc
Normal file
@@ -0,0 +1,159 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "impeller/renderer/capabilities.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
Capabilities::Capabilities() = default;
|
||||
|
||||
Capabilities::~Capabilities() = default;
|
||||
|
||||
class StandardCapabilities final : public Capabilities {
|
||||
public:
|
||||
// |Capabilities|
|
||||
~StandardCapabilities() override = default;
|
||||
|
||||
// |Capabilities|
|
||||
bool HasThreadingRestrictions() const override {
|
||||
return has_threading_restrictions_;
|
||||
}
|
||||
|
||||
// |Capabilities|
|
||||
bool SupportsOffscreenMSAA() const override {
|
||||
return supports_offscreen_msaa_;
|
||||
}
|
||||
|
||||
// |Capabilities|
|
||||
bool SupportsSSBO() const override { return supports_ssbo_; }
|
||||
|
||||
// |Capabilities|
|
||||
bool SupportsTextureToTextureBlits() const override {
|
||||
return supports_texture_to_texture_blits_;
|
||||
}
|
||||
|
||||
// |Capabilities|
|
||||
bool SupportsFramebufferFetch() const override {
|
||||
return supports_framebuffer_fetch_;
|
||||
}
|
||||
|
||||
// |Capabilities|
|
||||
bool SupportsCompute() const override { return supports_compute_; }
|
||||
|
||||
// |Capabilities|
|
||||
bool SupportsComputeSubgroups() const override {
|
||||
return supports_compute_subgroups_;
|
||||
}
|
||||
|
||||
// |Capabilities|
|
||||
PixelFormat GetDefaultColorFormat() const override {
|
||||
return default_color_format_;
|
||||
}
|
||||
|
||||
// |Capabilities|
|
||||
PixelFormat GetDefaultStencilFormat() const override {
|
||||
return default_stencil_format_;
|
||||
}
|
||||
|
||||
private:
|
||||
StandardCapabilities(bool has_threading_restrictions,
|
||||
bool supports_offscreen_msaa,
|
||||
bool supports_ssbo,
|
||||
bool supports_texture_to_texture_blits,
|
||||
bool supports_framebuffer_fetch,
|
||||
bool supports_compute,
|
||||
bool supports_compute_subgroups,
|
||||
PixelFormat default_color_format,
|
||||
PixelFormat default_stencil_format)
|
||||
: has_threading_restrictions_(has_threading_restrictions),
|
||||
supports_offscreen_msaa_(supports_offscreen_msaa),
|
||||
supports_ssbo_(supports_ssbo),
|
||||
supports_texture_to_texture_blits_(supports_texture_to_texture_blits),
|
||||
supports_framebuffer_fetch_(supports_framebuffer_fetch),
|
||||
supports_compute_(supports_compute),
|
||||
supports_compute_subgroups_(supports_compute_subgroups),
|
||||
default_color_format_(default_color_format),
|
||||
default_stencil_format_(default_stencil_format) {}
|
||||
|
||||
friend class CapabilitiesBuilder;
|
||||
|
||||
bool has_threading_restrictions_ = false;
|
||||
bool supports_offscreen_msaa_ = false;
|
||||
bool supports_ssbo_ = false;
|
||||
bool supports_texture_to_texture_blits_ = false;
|
||||
bool supports_framebuffer_fetch_ = false;
|
||||
bool supports_compute_ = false;
|
||||
bool supports_compute_subgroups_ = false;
|
||||
PixelFormat default_color_format_ = PixelFormat::kUnknown;
|
||||
PixelFormat default_stencil_format_ = PixelFormat::kUnknown;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(StandardCapabilities);
|
||||
};
|
||||
|
||||
CapabilitiesBuilder::CapabilitiesBuilder() = default;
|
||||
|
||||
CapabilitiesBuilder::~CapabilitiesBuilder() = default;
|
||||
|
||||
CapabilitiesBuilder& CapabilitiesBuilder::SetHasThreadingRestrictions(
|
||||
bool value) {
|
||||
has_threading_restrictions_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CapabilitiesBuilder& CapabilitiesBuilder::SetSupportsOffscreenMSAA(bool value) {
|
||||
supports_offscreen_msaa_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CapabilitiesBuilder& CapabilitiesBuilder::SetSupportsSSBO(bool value) {
|
||||
supports_ssbo_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CapabilitiesBuilder& CapabilitiesBuilder::SetSupportsTextureToTextureBlits(
|
||||
bool value) {
|
||||
supports_texture_to_texture_blits_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CapabilitiesBuilder& CapabilitiesBuilder::SetSupportsFramebufferFetch(
|
||||
bool value) {
|
||||
supports_framebuffer_fetch_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CapabilitiesBuilder& CapabilitiesBuilder::SetSupportsCompute(bool compute,
|
||||
bool subgroups) {
|
||||
supports_compute_ = compute;
|
||||
supports_compute_subgroups_ = subgroups;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CapabilitiesBuilder& CapabilitiesBuilder::SetDefaultColorFormat(
|
||||
PixelFormat value) {
|
||||
default_color_format_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CapabilitiesBuilder& CapabilitiesBuilder::SetDefaultStencilFormat(
|
||||
PixelFormat value) {
|
||||
default_stencil_format_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::unique_ptr<Capabilities> CapabilitiesBuilder::Build() {
|
||||
return std::unique_ptr<StandardCapabilities>(new StandardCapabilities( //
|
||||
has_threading_restrictions_, //
|
||||
supports_offscreen_msaa_, //
|
||||
supports_ssbo_, //
|
||||
supports_texture_to_texture_blits_, //
|
||||
supports_framebuffer_fetch_, //
|
||||
supports_compute_, //
|
||||
supports_compute_subgroups_, //
|
||||
*default_color_format_, //
|
||||
*default_stencil_format_ //
|
||||
));
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
80
engine/src/flutter/impeller/renderer/capabilities.h
Normal file
80
engine/src/flutter/impeller/renderer/capabilities.h
Normal file
@@ -0,0 +1,80 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/renderer/formats.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
class Capabilities {
|
||||
public:
|
||||
virtual ~Capabilities();
|
||||
|
||||
virtual bool HasThreadingRestrictions() const = 0;
|
||||
|
||||
virtual bool SupportsOffscreenMSAA() const = 0;
|
||||
|
||||
virtual bool SupportsSSBO() const = 0;
|
||||
|
||||
virtual bool SupportsTextureToTextureBlits() const = 0;
|
||||
|
||||
virtual bool SupportsFramebufferFetch() const = 0;
|
||||
|
||||
virtual bool SupportsCompute() const = 0;
|
||||
|
||||
virtual bool SupportsComputeSubgroups() const = 0;
|
||||
|
||||
virtual PixelFormat GetDefaultColorFormat() const = 0;
|
||||
|
||||
virtual PixelFormat GetDefaultStencilFormat() const = 0;
|
||||
|
||||
protected:
|
||||
Capabilities();
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(Capabilities);
|
||||
};
|
||||
|
||||
class CapabilitiesBuilder {
|
||||
public:
|
||||
CapabilitiesBuilder();
|
||||
|
||||
~CapabilitiesBuilder();
|
||||
|
||||
CapabilitiesBuilder& SetHasThreadingRestrictions(bool value);
|
||||
|
||||
CapabilitiesBuilder& SetSupportsOffscreenMSAA(bool value);
|
||||
|
||||
CapabilitiesBuilder& SetSupportsSSBO(bool value);
|
||||
|
||||
CapabilitiesBuilder& SetSupportsTextureToTextureBlits(bool value);
|
||||
|
||||
CapabilitiesBuilder& SetSupportsFramebufferFetch(bool value);
|
||||
|
||||
CapabilitiesBuilder& SetSupportsCompute(bool compute, bool subgroups);
|
||||
|
||||
CapabilitiesBuilder& SetDefaultColorFormat(PixelFormat value);
|
||||
|
||||
CapabilitiesBuilder& SetDefaultStencilFormat(PixelFormat value);
|
||||
|
||||
std::unique_ptr<Capabilities> Build();
|
||||
|
||||
private:
|
||||
bool has_threading_restrictions_ = false;
|
||||
bool supports_offscreen_msaa_ = false;
|
||||
bool supports_ssbo_ = false;
|
||||
bool supports_texture_to_texture_blits_ = false;
|
||||
bool supports_framebuffer_fetch_ = false;
|
||||
bool supports_compute_ = false;
|
||||
bool supports_compute_subgroups_ = false;
|
||||
std::optional<PixelFormat> default_color_format_ = std::nullopt;
|
||||
std::optional<PixelFormat> default_stencil_format_ = std::nullopt;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(CapabilitiesBuilder);
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
@@ -39,7 +39,7 @@ TEST_P(ComputeTest, HeartCubicsToStrokeVertices) {
|
||||
|
||||
auto context = GetContext();
|
||||
ASSERT_TRUE(context);
|
||||
ASSERT_TRUE(context->GetDeviceCapabilities().SupportsComputeSubgroups());
|
||||
ASSERT_TRUE(context->GetCapabilities()->SupportsComputeSubgroups());
|
||||
|
||||
auto cmd_buffer = context->CreateCommandBuffer();
|
||||
auto pass = cmd_buffer->CreateComputePass();
|
||||
@@ -258,7 +258,7 @@ TEST_P(ComputeTest, QuadsToPolyline) {
|
||||
using QS = QuadPolylineComputeShader;
|
||||
auto context = GetContext();
|
||||
ASSERT_TRUE(context);
|
||||
ASSERT_TRUE(context->GetDeviceCapabilities().SupportsComputeSubgroups());
|
||||
ASSERT_TRUE(context->GetCapabilities()->SupportsComputeSubgroups());
|
||||
|
||||
auto cmd_buffer = context->CreateCommandBuffer();
|
||||
auto pass = cmd_buffer->CreateComputePass();
|
||||
|
||||
@@ -28,7 +28,7 @@ TEST_P(ComputeTest, CanCreateComputePass) {
|
||||
using CS = SampleComputeShader;
|
||||
auto context = GetContext();
|
||||
ASSERT_TRUE(context);
|
||||
ASSERT_TRUE(context->GetDeviceCapabilities().SupportsCompute());
|
||||
ASSERT_TRUE(context->GetCapabilities()->SupportsCompute());
|
||||
|
||||
using SamplePipelineBuilder = ComputePipelineBuilder<CS>;
|
||||
auto pipeline_desc =
|
||||
@@ -111,7 +111,7 @@ TEST_P(ComputeTest, MultiStageInputAndOutput) {
|
||||
|
||||
auto context = GetContext();
|
||||
ASSERT_TRUE(context);
|
||||
ASSERT_TRUE(context->GetDeviceCapabilities().SupportsCompute());
|
||||
ASSERT_TRUE(context->GetCapabilities()->SupportsCompute());
|
||||
|
||||
auto pipeline_desc_1 =
|
||||
Stage1PipelineBuilder::MakeDefaultPipelineDescriptor(*context);
|
||||
|
||||
@@ -14,8 +14,8 @@ std::shared_ptr<GPUTracer> Context::GetGPUTracer() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PixelFormat Context::GetColorAttachmentPixelFormat() const {
|
||||
return GetDeviceCapabilities().GetDefaultColorFormat();
|
||||
bool Context::UpdateOffscreenLayerPixelFormat(PixelFormat format) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/renderer/device_capabilities.h"
|
||||
#include "impeller/renderer/capabilities.h"
|
||||
#include "impeller/renderer/formats.h"
|
||||
|
||||
namespace impeller {
|
||||
@@ -27,9 +27,11 @@ class Context : public std::enable_shared_from_this<Context> {
|
||||
|
||||
virtual bool IsValid() const = 0;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @return A resource allocator.
|
||||
///
|
||||
virtual const std::shared_ptr<const Capabilities>& GetCapabilities()
|
||||
const = 0;
|
||||
|
||||
virtual bool UpdateOffscreenLayerPixelFormat(PixelFormat format);
|
||||
|
||||
virtual std::shared_ptr<Allocator> GetResourceAllocator() const = 0;
|
||||
|
||||
virtual std::shared_ptr<ShaderLibrary> GetShaderLibrary() const = 0;
|
||||
@@ -42,15 +44,8 @@ class Context : public std::enable_shared_from_this<Context> {
|
||||
|
||||
virtual std::shared_ptr<WorkQueue> GetWorkQueue() const = 0;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @return A GPU Tracer to trace gpu rendering.
|
||||
///
|
||||
virtual std::shared_ptr<GPUTracer> GetGPUTracer() const;
|
||||
|
||||
virtual PixelFormat GetColorAttachmentPixelFormat() const;
|
||||
|
||||
virtual const IDeviceCapabilities& GetDeviceCapabilities() const = 0;
|
||||
|
||||
protected:
|
||||
Context();
|
||||
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/renderer/shader_types.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
enum class DescriptorType {
|
||||
kSampledImage,
|
||||
kUniformBuffer,
|
||||
};
|
||||
|
||||
struct DescriptorSetLayout {
|
||||
uint32_t binding;
|
||||
DescriptorType descriptor_type;
|
||||
uint32_t descriptor_count;
|
||||
ShaderStage shader_stage;
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
@@ -1,141 +0,0 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "impeller/renderer/device_capabilities.h"
|
||||
#include "device_capabilities.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
IDeviceCapabilities::IDeviceCapabilities(bool has_threading_restrictions,
|
||||
bool supports_offscreen_msaa,
|
||||
bool supports_ssbo,
|
||||
bool supports_texture_to_texture_blits,
|
||||
bool supports_framebuffer_fetch,
|
||||
PixelFormat default_color_format,
|
||||
PixelFormat default_stencil_format,
|
||||
bool supports_compute,
|
||||
bool supports_compute_subgroups)
|
||||
: has_threading_restrictions_(has_threading_restrictions),
|
||||
supports_offscreen_msaa_(supports_offscreen_msaa),
|
||||
supports_ssbo_(supports_ssbo),
|
||||
supports_texture_to_texture_blits_(supports_texture_to_texture_blits),
|
||||
supports_framebuffer_fetch_(supports_framebuffer_fetch),
|
||||
default_color_format_(default_color_format),
|
||||
default_stencil_format_(default_stencil_format),
|
||||
supports_compute_(supports_compute),
|
||||
supports_compute_subgroups_(supports_compute_subgroups) {}
|
||||
|
||||
IDeviceCapabilities::~IDeviceCapabilities() = default;
|
||||
|
||||
bool IDeviceCapabilities::HasThreadingRestrictions() const {
|
||||
return has_threading_restrictions_;
|
||||
}
|
||||
|
||||
bool IDeviceCapabilities::SupportsOffscreenMSAA() const {
|
||||
return supports_offscreen_msaa_;
|
||||
}
|
||||
|
||||
bool IDeviceCapabilities::SupportsSSBO() const {
|
||||
return supports_ssbo_;
|
||||
}
|
||||
|
||||
bool IDeviceCapabilities::SupportsTextureToTextureBlits() const {
|
||||
return supports_texture_to_texture_blits_;
|
||||
}
|
||||
|
||||
bool IDeviceCapabilities::SupportsFramebufferFetch() const {
|
||||
return supports_framebuffer_fetch_;
|
||||
}
|
||||
|
||||
PixelFormat IDeviceCapabilities::GetDefaultColorFormat() const {
|
||||
return default_color_format_;
|
||||
}
|
||||
|
||||
PixelFormat IDeviceCapabilities::GetDefaultStencilFormat() const {
|
||||
return default_stencil_format_;
|
||||
}
|
||||
|
||||
bool IDeviceCapabilities::SupportsCompute() const {
|
||||
return supports_compute_;
|
||||
}
|
||||
|
||||
bool IDeviceCapabilities::SupportsComputeSubgroups() const {
|
||||
return supports_compute_subgroups_;
|
||||
}
|
||||
|
||||
DeviceCapabilitiesBuilder::DeviceCapabilitiesBuilder() = default;
|
||||
|
||||
DeviceCapabilitiesBuilder::~DeviceCapabilitiesBuilder() = default;
|
||||
|
||||
DeviceCapabilitiesBuilder&
|
||||
DeviceCapabilitiesBuilder::SetHasThreadingRestrictions(bool value) {
|
||||
has_threading_restrictions_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
DeviceCapabilitiesBuilder& DeviceCapabilitiesBuilder::SetSupportsOffscreenMSAA(
|
||||
bool value) {
|
||||
supports_offscreen_msaa_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
DeviceCapabilitiesBuilder& DeviceCapabilitiesBuilder::SetSupportsSSBO(
|
||||
bool value) {
|
||||
supports_ssbo_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
DeviceCapabilitiesBuilder&
|
||||
DeviceCapabilitiesBuilder::SetSupportsTextureToTextureBlits(bool value) {
|
||||
supports_texture_to_texture_blits_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
DeviceCapabilitiesBuilder&
|
||||
DeviceCapabilitiesBuilder::SetSupportsFramebufferFetch(bool value) {
|
||||
supports_framebuffer_fetch_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
DeviceCapabilitiesBuilder& DeviceCapabilitiesBuilder::SetDefaultColorFormat(
|
||||
PixelFormat value) {
|
||||
default_color_format_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
DeviceCapabilitiesBuilder& DeviceCapabilitiesBuilder::SetDefaultStencilFormat(
|
||||
PixelFormat value) {
|
||||
default_stencil_format_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
DeviceCapabilitiesBuilder& DeviceCapabilitiesBuilder::SetSupportsCompute(
|
||||
bool value,
|
||||
bool subgroups) {
|
||||
supports_compute_ = value;
|
||||
supports_compute_subgroups_ = subgroups;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::unique_ptr<IDeviceCapabilities> DeviceCapabilitiesBuilder::Build() {
|
||||
FML_CHECK(default_color_format_.has_value())
|
||||
<< "Default color format not set";
|
||||
FML_CHECK(default_stencil_format_.has_value())
|
||||
<< "Default stencil format not set";
|
||||
|
||||
IDeviceCapabilities* capabilities = new IDeviceCapabilities( //
|
||||
has_threading_restrictions_, //
|
||||
supports_offscreen_msaa_, //
|
||||
supports_ssbo_, //
|
||||
supports_texture_to_texture_blits_, //
|
||||
supports_framebuffer_fetch_, //
|
||||
*default_color_format_, //
|
||||
*default_stencil_format_, //
|
||||
supports_compute_, //
|
||||
supports_compute_subgroups_ //
|
||||
);
|
||||
return std::unique_ptr<IDeviceCapabilities>(capabilities);
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
@@ -1,99 +0,0 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/renderer/formats.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
class IDeviceCapabilities {
|
||||
public:
|
||||
~IDeviceCapabilities();
|
||||
|
||||
bool HasThreadingRestrictions() const;
|
||||
|
||||
bool SupportsOffscreenMSAA() const;
|
||||
|
||||
bool SupportsSSBO() const;
|
||||
|
||||
bool SupportsTextureToTextureBlits() const;
|
||||
|
||||
bool SupportsFramebufferFetch() const;
|
||||
|
||||
PixelFormat GetDefaultColorFormat() const;
|
||||
|
||||
PixelFormat GetDefaultStencilFormat() const;
|
||||
|
||||
bool SupportsCompute() const;
|
||||
bool SupportsComputeSubgroups() const;
|
||||
|
||||
private:
|
||||
IDeviceCapabilities(bool has_threading_restrictions,
|
||||
bool supports_offscreen_msaa,
|
||||
bool supports_ssbo,
|
||||
bool supports_texture_to_texture_blits,
|
||||
bool supports_framebuffer_fetch,
|
||||
PixelFormat default_color_format,
|
||||
PixelFormat default_stencil_format,
|
||||
bool supports_compute,
|
||||
bool supports_compute_subgroups);
|
||||
|
||||
friend class DeviceCapabilitiesBuilder;
|
||||
|
||||
bool has_threading_restrictions_ = false;
|
||||
bool supports_offscreen_msaa_ = false;
|
||||
bool supports_ssbo_ = false;
|
||||
bool supports_texture_to_texture_blits_ = false;
|
||||
bool supports_framebuffer_fetch_ = false;
|
||||
PixelFormat default_color_format_;
|
||||
PixelFormat default_stencil_format_;
|
||||
bool supports_compute_ = false;
|
||||
bool supports_compute_subgroups_ = false;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(IDeviceCapabilities);
|
||||
};
|
||||
|
||||
class DeviceCapabilitiesBuilder {
|
||||
public:
|
||||
DeviceCapabilitiesBuilder();
|
||||
|
||||
~DeviceCapabilitiesBuilder();
|
||||
|
||||
DeviceCapabilitiesBuilder& SetHasThreadingRestrictions(bool value);
|
||||
|
||||
DeviceCapabilitiesBuilder& SetSupportsOffscreenMSAA(bool value);
|
||||
|
||||
DeviceCapabilitiesBuilder& SetSupportsSSBO(bool value);
|
||||
|
||||
DeviceCapabilitiesBuilder& SetSupportsTextureToTextureBlits(bool value);
|
||||
|
||||
DeviceCapabilitiesBuilder& SetSupportsFramebufferFetch(bool value);
|
||||
|
||||
DeviceCapabilitiesBuilder& SetDefaultColorFormat(PixelFormat value);
|
||||
|
||||
DeviceCapabilitiesBuilder& SetDefaultStencilFormat(PixelFormat value);
|
||||
|
||||
DeviceCapabilitiesBuilder& SetSupportsCompute(bool value, bool subgroups);
|
||||
|
||||
std::unique_ptr<IDeviceCapabilities> Build();
|
||||
|
||||
private:
|
||||
bool has_threading_restrictions_ = false;
|
||||
bool supports_offscreen_msaa_ = false;
|
||||
bool supports_ssbo_ = false;
|
||||
bool supports_texture_to_texture_blits_ = false;
|
||||
bool supports_framebuffer_fetch_ = false;
|
||||
bool supports_compute_ = false;
|
||||
bool supports_compute_subgroups_ = false;
|
||||
std::optional<PixelFormat> default_color_format_ = std::nullopt;
|
||||
std::optional<PixelFormat> default_stencil_format_ = std::nullopt;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(DeviceCapabilitiesBuilder);
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
@@ -188,6 +188,10 @@ enum class TextureUsage : TextureUsageMask {
|
||||
kRenderTarget = 1 << 2,
|
||||
};
|
||||
|
||||
constexpr bool TextureUsageIsRenderTarget(TextureUsageMask mask) {
|
||||
return static_cast<TextureUsageMask>(TextureUsage::kRenderTarget) & mask;
|
||||
}
|
||||
|
||||
enum class TextureIntent {
|
||||
kUploadFromHost,
|
||||
kRenderToTexture,
|
||||
|
||||
@@ -117,7 +117,7 @@ struct PipelineBuilder {
|
||||
// Configure the sole color attachments pixel format. This is by
|
||||
// convention.
|
||||
ColorAttachmentDescriptor color0;
|
||||
color0.format = context.GetColorAttachmentPixelFormat();
|
||||
color0.format = context.GetCapabilities()->GetDefaultColorFormat();
|
||||
color0.blending_enabled = true;
|
||||
desc.SetColorAttachmentDescriptor(0u, color0);
|
||||
}
|
||||
@@ -128,7 +128,7 @@ struct PipelineBuilder {
|
||||
stencil0.stencil_compare = CompareFunction::kEqual;
|
||||
desc.SetStencilAttachmentDescriptors(stencil0);
|
||||
desc.SetStencilPixelFormat(
|
||||
context.GetDeviceCapabilities().GetDefaultStencilFormat());
|
||||
context.GetCapabilities()->GetDefaultStencilFormat());
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -210,7 +210,7 @@ RenderTarget RenderTarget::CreateOffscreen(
|
||||
}
|
||||
|
||||
RenderTarget target;
|
||||
PixelFormat pixel_format = context.GetColorAttachmentPixelFormat();
|
||||
PixelFormat pixel_format = context.GetCapabilities()->GetDefaultColorFormat();
|
||||
TextureDescriptor color_tex0;
|
||||
color_tex0.storage_mode = color_attachment_config.storage_mode;
|
||||
color_tex0.format = pixel_format;
|
||||
@@ -233,8 +233,7 @@ RenderTarget RenderTarget::CreateOffscreen(
|
||||
if (stencil_attachment_config.has_value()) {
|
||||
TextureDescriptor stencil_tex0;
|
||||
stencil_tex0.storage_mode = stencil_attachment_config->storage_mode;
|
||||
stencil_tex0.format =
|
||||
context.GetDeviceCapabilities().GetDefaultStencilFormat();
|
||||
stencil_tex0.format = context.GetCapabilities()->GetDefaultStencilFormat();
|
||||
stencil_tex0.size = size;
|
||||
stencil_tex0.usage =
|
||||
static_cast<TextureUsageMask>(TextureUsage::kRenderTarget);
|
||||
@@ -269,7 +268,7 @@ RenderTarget RenderTarget::CreateOffscreenMSAA(
|
||||
}
|
||||
|
||||
RenderTarget target;
|
||||
PixelFormat pixel_format = context.GetColorAttachmentPixelFormat();
|
||||
PixelFormat pixel_format = context.GetCapabilities()->GetDefaultColorFormat();
|
||||
|
||||
// Create MSAA color texture.
|
||||
|
||||
@@ -327,8 +326,7 @@ RenderTarget RenderTarget::CreateOffscreenMSAA(
|
||||
stencil_tex0.storage_mode = stencil_attachment_config->storage_mode;
|
||||
stencil_tex0.type = TextureType::kTexture2DMultisample;
|
||||
stencil_tex0.sample_count = SampleCount::kCount4;
|
||||
stencil_tex0.format =
|
||||
context.GetDeviceCapabilities().GetDefaultStencilFormat();
|
||||
stencil_tex0.format = context.GetCapabilities()->GetDefaultStencilFormat();
|
||||
stencil_tex0.size = size;
|
||||
stencil_tex0.usage =
|
||||
static_cast<TextureUsageMask>(TextureUsage::kRenderTarget);
|
||||
|
||||
@@ -20,7 +20,7 @@ class Sampler {
|
||||
protected:
|
||||
SamplerDescriptor desc_;
|
||||
|
||||
Sampler(SamplerDescriptor desc);
|
||||
explicit Sampler(SamplerDescriptor desc);
|
||||
|
||||
private:
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(Sampler);
|
||||
|
||||
@@ -123,6 +123,17 @@ struct SampledImageSlot {
|
||||
constexpr bool HasSampler() const { return sampler_index < 32u; }
|
||||
};
|
||||
|
||||
enum class DescriptorType {
|
||||
kSampledImage,
|
||||
kUniformBuffer,
|
||||
};
|
||||
|
||||
struct DescriptorSetLayout {
|
||||
uint32_t binding;
|
||||
DescriptorType descriptor_type;
|
||||
ShaderStage shader_stage;
|
||||
};
|
||||
|
||||
template <size_t Size>
|
||||
struct Padding {
|
||||
private:
|
||||
|
||||
@@ -97,9 +97,8 @@ class MockImpellerContext : public Context {
|
||||
|
||||
MOCK_CONST_METHOD0(GetGPUTracer, std::shared_ptr<GPUTracer>());
|
||||
|
||||
MOCK_CONST_METHOD0(GetColorAttachmentPixelFormat, PixelFormat());
|
||||
|
||||
MOCK_CONST_METHOD0(GetDeviceCapabilities, const IDeviceCapabilities&());
|
||||
MOCK_CONST_METHOD0(GetCapabilities,
|
||||
const std::shared_ptr<const Capabilities>&());
|
||||
};
|
||||
|
||||
class MockTexture : public Texture {
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/base/comparable.h"
|
||||
#include "impeller/renderer/descriptor_set_layout.h"
|
||||
#include "impeller/renderer/shader_types.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
@@ -242,13 +242,13 @@ TEST_P(RuntimeStageTest, CanCreatePipelineFromRuntimeStage) {
|
||||
ASSERT_TRUE(vertex_descriptor->SetStageInputs(VS::kAllShaderStageInputs));
|
||||
desc.SetVertexDescriptor(std::move(vertex_descriptor));
|
||||
ColorAttachmentDescriptor color0;
|
||||
color0.format = GetContext()->GetColorAttachmentPixelFormat();
|
||||
color0.format = GetContext()->GetCapabilities()->GetDefaultColorFormat();
|
||||
StencilAttachmentDescriptor stencil0;
|
||||
stencil0.stencil_compare = CompareFunction::kEqual;
|
||||
desc.SetColorAttachmentDescriptor(0u, color0);
|
||||
desc.SetStencilAttachmentDescriptors(stencil0);
|
||||
const auto stencil_fmt =
|
||||
GetContext()->GetDeviceCapabilities().GetDefaultStencilFormat();
|
||||
GetContext()->GetCapabilities()->GetDefaultStencilFormat();
|
||||
desc.SetStencilPixelFormat(stencil_fmt);
|
||||
auto pipeline = GetContext()->GetPipelineLibrary()->GetPipeline(desc).Get();
|
||||
ASSERT_NE(pipeline, nullptr);
|
||||
|
||||
@@ -325,7 +325,7 @@ void ImageDecoderImpeller::Decode(fml::RefPtr<ImageDescriptor> descriptor,
|
||||
// Depending on whether the context has threading restrictions, stay on
|
||||
// the concurrent runner to perform texture upload or move to an IO
|
||||
// runner.
|
||||
if (context->GetDeviceCapabilities().HasThreadingRestrictions()) {
|
||||
if (context->GetCapabilities()->HasThreadingRestrictions()) {
|
||||
io_runner->PostTask(upload_texture_and_invoke_result);
|
||||
} else {
|
||||
upload_texture_and_invoke_result();
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
#include "flutter/impeller/renderer/context.h"
|
||||
#include "flutter/shell/gpu/gpu_surface_metal_impeller.h"
|
||||
|
||||
namespace {
|
||||
impeller::PixelFormat InferOffscreenLayerPixelFormat(impeller::PixelFormat pixel_format) {
|
||||
namespace flutter {
|
||||
|
||||
static impeller::PixelFormat InferOffscreenLayerPixelFormat(impeller::PixelFormat pixel_format) {
|
||||
switch (pixel_format) {
|
||||
case impeller::PixelFormat::kB10G10R10XR:
|
||||
return impeller::PixelFormat::kB10G10R10A10XR;
|
||||
@@ -17,66 +18,6 @@ impeller::PixelFormat InferOffscreenLayerPixelFormat(impeller::PixelFormat pixel
|
||||
return pixel_format;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace impeller {
|
||||
namespace {
|
||||
// This appears to be the only safe way to override the
|
||||
// GetColorAttachmentPixelFormat method. It is assumed in the Context that
|
||||
// there will be one pixel format for the whole app which is not true. So, it
|
||||
// is unsafe to mutate the Context and you cannot clone the Context at this
|
||||
// level since the Context does not safely manage the MTLDevice.
|
||||
class CustomColorAttachmentPixelFormatContext final : public Context {
|
||||
public:
|
||||
CustomColorAttachmentPixelFormatContext(const std::shared_ptr<Context>& context,
|
||||
PixelFormat color_attachment_pixel_format)
|
||||
: context_(context), color_attachment_pixel_format_(color_attachment_pixel_format) {}
|
||||
|
||||
bool IsValid() const override { return context_->IsValid(); }
|
||||
|
||||
std::shared_ptr<Allocator> GetResourceAllocator() const override {
|
||||
return context_->GetResourceAllocator();
|
||||
}
|
||||
|
||||
std::shared_ptr<ShaderLibrary> GetShaderLibrary() const override {
|
||||
return context_->GetShaderLibrary();
|
||||
}
|
||||
|
||||
std::shared_ptr<SamplerLibrary> GetSamplerLibrary() const override {
|
||||
return context_->GetSamplerLibrary();
|
||||
}
|
||||
|
||||
std::shared_ptr<PipelineLibrary> GetPipelineLibrary() const override {
|
||||
return context_->GetPipelineLibrary();
|
||||
}
|
||||
|
||||
std::shared_ptr<CommandBuffer> CreateCommandBuffer() const override {
|
||||
return context_->CreateCommandBuffer();
|
||||
}
|
||||
|
||||
std::shared_ptr<WorkQueue> GetWorkQueue() const override { return context_->GetWorkQueue(); }
|
||||
|
||||
std::shared_ptr<GPUTracer> GetGPUTracer() const override { return context_->GetGPUTracer(); }
|
||||
|
||||
PixelFormat GetColorAttachmentPixelFormat() const override {
|
||||
return color_attachment_pixel_format_;
|
||||
}
|
||||
|
||||
const IDeviceCapabilities& GetDeviceCapabilities() const override {
|
||||
return context_->GetDeviceCapabilities();
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<Context> context_;
|
||||
PixelFormat color_attachment_pixel_format_;
|
||||
};
|
||||
} // namespace
|
||||
} // namespace impeller
|
||||
|
||||
namespace flutter {
|
||||
|
||||
using impeller::CustomColorAttachmentPixelFormatContext;
|
||||
using impeller::FromMTLPixelFormat;
|
||||
|
||||
IOSSurfaceMetalImpeller::IOSSurfaceMetalImpeller(const fml::scoped_nsobject<CAMetalLayer>& layer,
|
||||
const std::shared_ptr<IOSContext>& context)
|
||||
@@ -87,7 +28,8 @@ IOSSurfaceMetalImpeller::IOSSurfaceMetalImpeller(const fml::scoped_nsobject<CAMe
|
||||
if (!impeller_context_) {
|
||||
return;
|
||||
}
|
||||
is_valid_ = true;
|
||||
is_valid_ = impeller_context_->UpdateOffscreenLayerPixelFormat(
|
||||
InferOffscreenLayerPixelFormat(impeller::FromMTLPixelFormat(layer_.get().pixelFormat)));
|
||||
}
|
||||
|
||||
// |IOSSurface|
|
||||
@@ -105,11 +47,8 @@ void IOSSurfaceMetalImpeller::UpdateStorageSizeIfNecessary() {
|
||||
|
||||
// |IOSSurface|
|
||||
std::unique_ptr<Surface> IOSSurfaceMetalImpeller::CreateGPUSurface(GrDirectContext*) {
|
||||
auto context = std::make_shared<CustomColorAttachmentPixelFormatContext>(
|
||||
impeller_context_,
|
||||
InferOffscreenLayerPixelFormat(FromMTLPixelFormat(layer_.get().pixelFormat)));
|
||||
return std::make_unique<GPUSurfaceMetalImpeller>(this, //
|
||||
context //
|
||||
return std::make_unique<GPUSurfaceMetalImpeller>(this, //
|
||||
impeller_context_ //
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user