mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[Impeller] Add blit pass (flutter/engine#34901)
This commit is contained in:
parent
d560fa20d1
commit
92a7cfe151
@ -671,6 +671,10 @@ FILE: ../../../flutter/impeller/renderer/allocator.cc
|
||||
FILE: ../../../flutter/impeller/renderer/allocator.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/gles/allocator_gles.cc
|
||||
FILE: ../../../flutter/impeller/renderer/backend/gles/allocator_gles.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/gles/blit_command_gles.cc
|
||||
FILE: ../../../flutter/impeller/renderer/backend/gles/blit_command_gles.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/gles/blit_pass_gles.cc
|
||||
FILE: ../../../flutter/impeller/renderer/backend/gles/blit_pass_gles.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/gles/buffer_bindings_gles.cc
|
||||
FILE: ../../../flutter/impeller/renderer/backend/gles/buffer_bindings_gles.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/gles/capabilities_gles.cc
|
||||
@ -712,6 +716,10 @@ FILE: ../../../flutter/impeller/renderer/backend/gles/texture_gles.cc
|
||||
FILE: ../../../flutter/impeller/renderer/backend/gles/texture_gles.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/metal/allocator_mtl.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/metal/allocator_mtl.mm
|
||||
FILE: ../../../flutter/impeller/renderer/backend/metal/blit_command_mtl.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/metal/blit_command_mtl.mm
|
||||
FILE: ../../../flutter/impeller/renderer/backend/metal/blit_pass_mtl.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/metal/blit_pass_mtl.mm
|
||||
FILE: ../../../flutter/impeller/renderer/backend/metal/command_buffer_mtl.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/metal/command_buffer_mtl.mm
|
||||
FILE: ../../../flutter/impeller/renderer/backend/metal/context_mtl.h
|
||||
@ -742,6 +750,8 @@ FILE: ../../../flutter/impeller/renderer/backend/metal/vertex_descriptor_mtl.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/metal/vertex_descriptor_mtl.mm
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/allocator_vk.cc
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/allocator_vk.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/blit_pass_vk.cc
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/blit_pass_vk.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/capabilities_vk.cc
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/capabilities_vk.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/command_buffer_vk.cc
|
||||
@ -773,6 +783,10 @@ FILE: ../../../flutter/impeller/renderer/backend/vulkan/texture_vk.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/vertex_descriptor_vk.cc
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/vertex_descriptor_vk.h
|
||||
FILE: ../../../flutter/impeller/renderer/backend/vulkan/vk.h
|
||||
FILE: ../../../flutter/impeller/renderer/blit_command.cc
|
||||
FILE: ../../../flutter/impeller/renderer/blit_command.h
|
||||
FILE: ../../../flutter/impeller/renderer/blit_pass.cc
|
||||
FILE: ../../../flutter/impeller/renderer/blit_pass.h
|
||||
FILE: ../../../flutter/impeller/renderer/buffer.cc
|
||||
FILE: ../../../flutter/impeller/renderer/buffer.h
|
||||
FILE: ../../../flutter/impeller/renderer/buffer_view.cc
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
#include "impeller/geometry/path_builder.h"
|
||||
#include "impeller/geometry/scalar.h"
|
||||
#include "impeller/geometry/vertices.h"
|
||||
#include "impeller/renderer/formats.h"
|
||||
#include "impeller/typographer/backends/skia/text_frame_skia.h"
|
||||
|
||||
#include "third_party/skia/include/core/SkColor.h"
|
||||
@ -778,6 +779,11 @@ static impeller::SamplerDescriptor ToSamplerDescriptor(
|
||||
desc.min_filter = desc.mag_filter = impeller::MinMagFilter::kLinear;
|
||||
desc.label = "Linear Sampler";
|
||||
break;
|
||||
case flutter::DlImageSampling::kMipmapLinear:
|
||||
desc.min_filter = desc.mag_filter = impeller::MinMagFilter::kLinear;
|
||||
desc.mip_filter = impeller::MipFilter::kLinear;
|
||||
desc.label = "Mipmap Linear Sampler";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@ -16,6 +16,8 @@ impeller_shaders("shader_fixtures") {
|
||||
"impeller.vert",
|
||||
"instanced_draw.frag",
|
||||
"instanced_draw.vert",
|
||||
"mipmaps.frag",
|
||||
"mipmaps.vert",
|
||||
"simple.vert",
|
||||
"test_texture.frag",
|
||||
"test_texture.vert",
|
||||
|
||||
18
engine/src/flutter/impeller/fixtures/mipmaps.frag
Normal file
18
engine/src/flutter/impeller/fixtures/mipmaps.frag
Normal file
@ -0,0 +1,18 @@
|
||||
// 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.
|
||||
|
||||
uniform FragInfo {
|
||||
float lod;
|
||||
}
|
||||
frag_info;
|
||||
|
||||
uniform sampler2D tex;
|
||||
|
||||
in vec2 v_uv;
|
||||
|
||||
out vec4 frag_color;
|
||||
|
||||
void main() {
|
||||
frag_color = textureLod(tex, v_uv, frag_info.lod);
|
||||
}
|
||||
18
engine/src/flutter/impeller/fixtures/mipmaps.vert
Normal file
18
engine/src/flutter/impeller/fixtures/mipmaps.vert
Normal file
@ -0,0 +1,18 @@
|
||||
// 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.
|
||||
|
||||
uniform VertInfo {
|
||||
mat4 mvp;
|
||||
}
|
||||
vert_info;
|
||||
|
||||
in vec2 vertex_position;
|
||||
in vec2 uv;
|
||||
|
||||
out vec2 v_uv;
|
||||
|
||||
void main() {
|
||||
gl_Position = vert_info.mvp * vec4(vertex_position, 0.0, 1.0);
|
||||
v_uv = uv;
|
||||
}
|
||||
@ -334,7 +334,8 @@ std::optional<DecompressedImage> Playground::LoadFixtureImageRGBA(
|
||||
}
|
||||
|
||||
std::shared_ptr<Texture> Playground::CreateTextureForFixture(
|
||||
const char* fixture_name) const {
|
||||
const char* fixture_name,
|
||||
bool enable_mipmapping) const {
|
||||
auto image = LoadFixtureImageRGBA(fixture_name);
|
||||
if (!image.has_value()) {
|
||||
return nullptr;
|
||||
@ -343,7 +344,8 @@ std::shared_ptr<Texture> Playground::CreateTextureForFixture(
|
||||
auto texture_descriptor = TextureDescriptor{};
|
||||
texture_descriptor.format = PixelFormat::kR8G8B8A8UNormInt;
|
||||
texture_descriptor.size = image->GetSize();
|
||||
texture_descriptor.mip_count = 1u;
|
||||
texture_descriptor.mip_count =
|
||||
enable_mipmapping ? image->GetSize().MipCount() : 1u;
|
||||
|
||||
auto texture =
|
||||
renderer_->GetContext()->GetPermanentsAllocator()->CreateTexture(
|
||||
|
||||
@ -57,7 +57,8 @@ class Playground : public ::testing::TestWithParam<PlaygroundBackend> {
|
||||
const char* fixture_name) const;
|
||||
|
||||
std::shared_ptr<Texture> CreateTextureForFixture(
|
||||
const char* fixture_name) const;
|
||||
const char* fixture_name,
|
||||
bool enable_mipmapping = false) const;
|
||||
|
||||
std::shared_ptr<Texture> CreateTextureCubeForFixture(
|
||||
std::array<const char*, 6> fixture_names) const;
|
||||
|
||||
@ -8,6 +8,10 @@ impeller_component("renderer") {
|
||||
sources = [
|
||||
"allocator.cc",
|
||||
"allocator.h",
|
||||
"blit_command.cc",
|
||||
"blit_command.h",
|
||||
"blit_pass.cc",
|
||||
"blit_pass.h",
|
||||
"buffer.cc",
|
||||
"buffer.h",
|
||||
"buffer_view.cc",
|
||||
|
||||
@ -16,6 +16,10 @@ impeller_component("gles") {
|
||||
sources = [
|
||||
"allocator_gles.cc",
|
||||
"allocator_gles.h",
|
||||
"blit_command_gles.cc",
|
||||
"blit_command_gles.h",
|
||||
"blit_pass_gles.cc",
|
||||
"blit_pass_gles.h",
|
||||
"buffer_bindings_gles.cc",
|
||||
"buffer_bindings_gles.h",
|
||||
"capabilities_gles.cc",
|
||||
@ -60,8 +64,11 @@ impeller_component("gles") {
|
||||
if (!is_android && !is_fuchsia) {
|
||||
public_configs = [ ":gles_config" ]
|
||||
sources += [
|
||||
"//third_party/angle/include/GLES2/gl2.h",
|
||||
"//third_party/angle/include/GLES2/gl2ext.h",
|
||||
|
||||
# The GLES3 API is a superset of GLES2. Although we target GLES2, we use
|
||||
# some GLES3 features if the driver supports them.
|
||||
"//third_party/angle/include/GLES3/gl3.h",
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,134 @@
|
||||
// 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/gles/blit_command_gles.h"
|
||||
|
||||
#include "flutter/fml/closure.h"
|
||||
#include "impeller/base/validation.h"
|
||||
#include "impeller/renderer/backend/gles/texture_gles.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
BlitEncodeGLES::~BlitEncodeGLES() = default;
|
||||
|
||||
static void DeleteFBO(const ProcTableGLES& gl, GLuint fbo, GLenum type) {
|
||||
if (fbo != GL_NONE) {
|
||||
gl.BindFramebuffer(type, GL_NONE);
|
||||
gl.DeleteFramebuffers(1u, &fbo);
|
||||
}
|
||||
};
|
||||
|
||||
static std::optional<GLuint> ConfigureFBO(
|
||||
const ProcTableGLES& gl,
|
||||
const std::shared_ptr<Texture>& texture,
|
||||
GLenum fbo_type) {
|
||||
auto handle = TextureGLES::Cast(texture.get())->GetGLHandle();
|
||||
if (!handle.has_value()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (TextureGLES::Cast(*texture).IsWrapped()) {
|
||||
// The texture is attached to the default FBO, so there's no need to
|
||||
// create/configure one.
|
||||
gl.BindFramebuffer(fbo_type, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLuint fbo;
|
||||
gl.GenFramebuffers(1u, &fbo);
|
||||
gl.BindFramebuffer(fbo_type, fbo);
|
||||
|
||||
if (!TextureGLES::Cast(*texture).SetAsFramebufferAttachment(
|
||||
fbo_type, fbo, TextureGLES::AttachmentPoint::kColor0)) {
|
||||
VALIDATION_LOG << "Could not attach texture to framebuffer.";
|
||||
DeleteFBO(gl, fbo, fbo_type);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (gl.CheckFramebufferStatus(fbo_type) != GL_FRAMEBUFFER_COMPLETE) {
|
||||
VALIDATION_LOG << "Could not create a complete frambuffer.";
|
||||
DeleteFBO(gl, fbo, fbo_type);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return fbo;
|
||||
};
|
||||
|
||||
BlitCopyTextureToTextureCommandGLES::~BlitCopyTextureToTextureCommandGLES() =
|
||||
default;
|
||||
|
||||
std::string BlitCopyTextureToTextureCommandGLES::GetLabel() const {
|
||||
return label;
|
||||
}
|
||||
|
||||
bool BlitCopyTextureToTextureCommandGLES::Encode(
|
||||
const ReactorGLES& reactor) const {
|
||||
const auto& gl = reactor.GetProcTable();
|
||||
|
||||
// glBlitFramebuffer is a GLES3 proc. Since we target GLES2, we need to
|
||||
// emulate the blit when it's not available in the driver.
|
||||
if (!gl.BlitFramebuffer.IsAvailable()) {
|
||||
// TODO(bdero): Emulate the blit using a raster draw call here.
|
||||
FML_LOG(ERROR) << "Texture blit fallback not implemented yet for GLES2.";
|
||||
return false;
|
||||
}
|
||||
|
||||
GLuint read_fbo = GL_NONE;
|
||||
GLuint draw_fbo = GL_NONE;
|
||||
fml::ScopedCleanupClosure delete_fbos([&gl, &read_fbo, &draw_fbo]() {
|
||||
DeleteFBO(gl, read_fbo, GL_READ_FRAMEBUFFER);
|
||||
DeleteFBO(gl, draw_fbo, GL_DRAW_FRAMEBUFFER);
|
||||
});
|
||||
|
||||
{
|
||||
auto read = ConfigureFBO(gl, source, GL_READ_FRAMEBUFFER);
|
||||
if (!read.has_value()) {
|
||||
return false;
|
||||
}
|
||||
read_fbo = read.value();
|
||||
}
|
||||
|
||||
{
|
||||
auto draw = ConfigureFBO(gl, destination, GL_DRAW_FRAMEBUFFER);
|
||||
if (!draw.has_value()) {
|
||||
return false;
|
||||
}
|
||||
draw_fbo = draw.value();
|
||||
}
|
||||
|
||||
gl.Disable(GL_SCISSOR_TEST);
|
||||
gl.Disable(GL_DEPTH_TEST);
|
||||
gl.Disable(GL_STENCIL_TEST);
|
||||
|
||||
gl.BlitFramebuffer(source_region.origin.x, // srcX0
|
||||
source_region.origin.y, // srcY0
|
||||
source_region.size.width, // srcX1
|
||||
source_region.size.height, // srcY1
|
||||
destination_origin.x, // dstX0
|
||||
destination_origin.y, // dstY0
|
||||
source_region.size.width, // dstX1
|
||||
source_region.size.height, // dstY1
|
||||
GL_COLOR_BUFFER_BIT, // mask
|
||||
GL_NEAREST // filter
|
||||
);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
BlitGenerateMipmapCommandGLES::~BlitGenerateMipmapCommandGLES() = default;
|
||||
|
||||
std::string BlitGenerateMipmapCommandGLES::GetLabel() const {
|
||||
return label;
|
||||
}
|
||||
|
||||
bool BlitGenerateMipmapCommandGLES::Encode(const ReactorGLES& reactor) const {
|
||||
auto texture_gles = TextureGLES::Cast(texture.get());
|
||||
if (!texture_gles->GenerateMipmaps()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
@ -0,0 +1,41 @@
|
||||
// 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 "impeller/base/backend_cast.h"
|
||||
#include "impeller/renderer/backend/gles/reactor_gles.h"
|
||||
#include "impeller/renderer/blit_command.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
/// Mixin for dispatching GLES commands.
|
||||
struct BlitEncodeGLES : BackendCast<BlitEncodeGLES, BlitCommand> {
|
||||
virtual ~BlitEncodeGLES();
|
||||
|
||||
virtual std::string GetLabel() const = 0;
|
||||
|
||||
[[nodiscard]] virtual bool Encode(const ReactorGLES& reactor) const = 0;
|
||||
};
|
||||
|
||||
struct BlitCopyTextureToTextureCommandGLES
|
||||
: public BlitEncodeGLES,
|
||||
public BlitCopyTextureToTextureCommand {
|
||||
~BlitCopyTextureToTextureCommandGLES() override;
|
||||
|
||||
std::string GetLabel() const override;
|
||||
|
||||
[[nodiscard]] bool Encode(const ReactorGLES& reactor) const override;
|
||||
};
|
||||
|
||||
struct BlitGenerateMipmapCommandGLES : public BlitEncodeGLES,
|
||||
public BlitGenerateMipmapCommand {
|
||||
~BlitGenerateMipmapCommandGLES() override;
|
||||
|
||||
std::string GetLabel() const override;
|
||||
|
||||
[[nodiscard]] bool Encode(const ReactorGLES& reactor) const override;
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
@ -0,0 +1,124 @@
|
||||
// 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/gles/blit_pass_gles.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#include "flutter/fml/trace_event.h"
|
||||
#include "impeller/base/config.h"
|
||||
#include "impeller/base/validation.h"
|
||||
#include "impeller/renderer/backend/gles/blit_command_gles.h"
|
||||
#include "impeller/renderer/backend/gles/device_buffer_gles.h"
|
||||
#include "impeller/renderer/backend/gles/formats_gles.h"
|
||||
#include "impeller/renderer/backend/gles/pipeline_gles.h"
|
||||
#include "impeller/renderer/backend/gles/proc_table_gles.h"
|
||||
#include "impeller/renderer/backend/gles/texture_gles.h"
|
||||
#include "impeller/renderer/formats.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
BlitPassGLES::BlitPassGLES(ReactorGLES::Ref reactor)
|
||||
: reactor_(std::move(reactor)),
|
||||
is_valid_(reactor_ && reactor_->IsValid()) {}
|
||||
|
||||
// |BlitPass|
|
||||
BlitPassGLES::~BlitPassGLES() = default;
|
||||
|
||||
// |BlitPass|
|
||||
bool BlitPassGLES::IsValid() const {
|
||||
return is_valid_;
|
||||
}
|
||||
|
||||
// |BlitPass|
|
||||
void BlitPassGLES::OnSetLabel(std::string label) {
|
||||
label_ = std::move(label);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool EncodeCommandsInReactor(
|
||||
const std::shared_ptr<Allocator>& transients_allocator,
|
||||
const ReactorGLES& reactor,
|
||||
const std::vector<std::unique_ptr<BlitEncodeGLES>>& commands,
|
||||
const std::string& label) {
|
||||
TRACE_EVENT0("impeller", __FUNCTION__);
|
||||
|
||||
if (commands.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto& gl = reactor.GetProcTable();
|
||||
|
||||
fml::ScopedCleanupClosure pop_pass_debug_marker(
|
||||
[&gl]() { gl.PopDebugGroup(); });
|
||||
if (!label.empty()) {
|
||||
gl.PushDebugGroup(label);
|
||||
} else {
|
||||
pop_pass_debug_marker.Release();
|
||||
}
|
||||
|
||||
for (const auto& command : commands) {
|
||||
fml::ScopedCleanupClosure pop_cmd_debug_marker(
|
||||
[&gl]() { gl.PopDebugGroup(); });
|
||||
auto label = command->GetLabel();
|
||||
if (!label.empty()) {
|
||||
gl.PushDebugGroup(label);
|
||||
} else {
|
||||
pop_cmd_debug_marker.Release();
|
||||
}
|
||||
|
||||
if (!command->Encode(reactor)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// |BlitPass|
|
||||
bool BlitPassGLES::EncodeCommands(
|
||||
const std::shared_ptr<Allocator>& transients_allocator) const {
|
||||
if (!IsValid()) {
|
||||
return false;
|
||||
}
|
||||
if (commands_.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return reactor_->AddOperation([transients_allocator, &commands = commands_,
|
||||
label = label_](const auto& reactor) {
|
||||
auto result =
|
||||
EncodeCommandsInReactor(transients_allocator, reactor, commands, label);
|
||||
FML_CHECK(result) << "Must be able to encode GL commands without error.";
|
||||
});
|
||||
}
|
||||
|
||||
// |BlitPass|
|
||||
void BlitPassGLES::OnCopyTextureToTextureCommand(
|
||||
std::shared_ptr<Texture> source,
|
||||
std::shared_ptr<Texture> destination,
|
||||
IRect source_region,
|
||||
IPoint destination_origin,
|
||||
std::string label) {
|
||||
auto command = std::make_unique<BlitCopyTextureToTextureCommandGLES>();
|
||||
command->label = label;
|
||||
command->source = std::move(source);
|
||||
command->destination = std::move(destination);
|
||||
command->source_region = source_region;
|
||||
command->destination_origin = destination_origin;
|
||||
|
||||
commands_.emplace_back(std::move(command));
|
||||
}
|
||||
|
||||
// |BlitPass|
|
||||
void BlitPassGLES::OnGenerateMipmapCommand(std::shared_ptr<Texture> texture,
|
||||
std::string label) {
|
||||
auto command = std::make_unique<BlitGenerateMipmapCommandGLES>();
|
||||
command->label = label;
|
||||
command->texture = std::move(texture);
|
||||
|
||||
commands_.emplace_back(std::move(command));
|
||||
}
|
||||
|
||||
} // 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 "flutter/fml/macros.h"
|
||||
#include "flutter/impeller/renderer/backend/gles/reactor_gles.h"
|
||||
#include "flutter/impeller/renderer/blit_pass.h"
|
||||
#include "impeller/renderer/backend/gles/blit_command_gles.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
class BlitPassGLES final : public BlitPass {
|
||||
public:
|
||||
// |BlitPass|
|
||||
~BlitPassGLES() override;
|
||||
|
||||
private:
|
||||
friend class CommandBufferGLES;
|
||||
|
||||
std::vector<std::unique_ptr<BlitEncodeGLES>> commands_;
|
||||
ReactorGLES::Ref reactor_;
|
||||
std::string label_;
|
||||
bool is_valid_ = false;
|
||||
|
||||
explicit BlitPassGLES(ReactorGLES::Ref reactor);
|
||||
|
||||
// |BlitPass|
|
||||
bool IsValid() const override;
|
||||
|
||||
// |BlitPass|
|
||||
void OnSetLabel(std::string label) override;
|
||||
|
||||
// |BlitPass|
|
||||
bool EncodeCommands(
|
||||
const std::shared_ptr<Allocator>& transients_allocator) const override;
|
||||
|
||||
// |BlitPass|
|
||||
void OnCopyTextureToTextureCommand(std::shared_ptr<Texture> source,
|
||||
std::shared_ptr<Texture> destination,
|
||||
IRect source_region,
|
||||
IPoint destination_origin,
|
||||
std::string label) override;
|
||||
|
||||
// |BlitPass|
|
||||
void OnGenerateMipmapCommand(std::shared_ptr<Texture> texture,
|
||||
std::string label) override;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(BlitPassGLES);
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
@ -5,6 +5,7 @@
|
||||
#include "impeller/renderer/backend/gles/command_buffer_gles.h"
|
||||
|
||||
#include "impeller/base/config.h"
|
||||
#include "impeller/renderer/backend/gles/blit_pass_gles.h"
|
||||
#include "impeller/renderer/backend/gles/render_pass_gles.h"
|
||||
|
||||
namespace impeller {
|
||||
@ -54,4 +55,16 @@ std::shared_ptr<RenderPass> CommandBufferGLES::OnCreateRenderPass(
|
||||
return pass;
|
||||
}
|
||||
|
||||
// |CommandBuffer|
|
||||
std::shared_ptr<BlitPass> CommandBufferGLES::OnCreateBlitPass() const {
|
||||
if (!IsValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
auto pass = std::shared_ptr<BlitPassGLES>(new BlitPassGLES(reactor_));
|
||||
if (!pass->IsValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
return pass;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@ -37,6 +37,9 @@ class CommandBufferGLES final : public CommandBuffer {
|
||||
std::shared_ptr<RenderPass> OnCreateRenderPass(
|
||||
RenderTarget target) const override;
|
||||
|
||||
// |CommandBuffer|
|
||||
std::shared_ptr<BlitPass> OnCreateBlitPass() const override;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(CommandBufferGLES);
|
||||
};
|
||||
|
||||
|
||||
@ -163,6 +163,18 @@ constexpr std::optional<GLenum> ToVertexAttribType(ShaderType type) {
|
||||
FML_UNREACHABLE();
|
||||
}
|
||||
|
||||
constexpr GLenum ToTextureType(TextureType type) {
|
||||
switch (type) {
|
||||
case TextureType::kTexture2D:
|
||||
return GL_TEXTURE_2D;
|
||||
case TextureType::kTexture2DMultisample:
|
||||
return GL_TEXTURE_2D_MULTISAMPLE;
|
||||
case TextureType::kTextureCube:
|
||||
return GL_TEXTURE_CUBE_MAP;
|
||||
}
|
||||
FML_UNREACHABLE();
|
||||
}
|
||||
|
||||
constexpr std::optional<GLenum> ToTextureTarget(TextureType type) {
|
||||
switch (type) {
|
||||
case TextureType::kTexture2D:
|
||||
|
||||
@ -4,6 +4,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GLES2/gl2.h"
|
||||
#include "GLES3/gl3.h"
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include "GLES2/gl2ext.h"
|
||||
|
||||
@ -87,6 +87,7 @@ ProcTableGLES::ProcTableGLES(Resolver resolver) {
|
||||
reinterpret_cast<decltype(proc_ivar.function)>(fn_ptr); \
|
||||
proc_ivar.error_fn = error_fn; \
|
||||
}
|
||||
FOR_EACH_IMPELLER_GLES3_PROC(IMPELLER_PROC);
|
||||
FOR_EACH_IMPELLER_EXT_PROC(IMPELLER_PROC);
|
||||
|
||||
#undef IMPELLER_PROC
|
||||
|
||||
@ -123,6 +123,7 @@ struct GLProc {
|
||||
PROC(FramebufferTexture2D); \
|
||||
PROC(FrontFace); \
|
||||
PROC(GenBuffers); \
|
||||
PROC(GenerateMipmap); \
|
||||
PROC(GenFramebuffers); \
|
||||
PROC(GenRenderbuffers); \
|
||||
PROC(GenTextures); \
|
||||
@ -162,6 +163,8 @@ struct GLProc {
|
||||
PROC(VertexAttribPointer); \
|
||||
PROC(Viewport);
|
||||
|
||||
#define FOR_EACH_IMPELLER_GLES3_PROC(PROC) PROC(BlitFramebuffer);
|
||||
|
||||
#define FOR_EACH_IMPELLER_EXT_PROC(PROC) \
|
||||
PROC(DiscardFramebufferEXT); \
|
||||
PROC(PushDebugGroupKHR); \
|
||||
@ -188,6 +191,7 @@ class ProcTableGLES {
|
||||
GLProc<decltype(gl##name)> name = {"gl" #name, nullptr};
|
||||
|
||||
FOR_EACH_IMPELLER_PROC(IMPELLER_PROC);
|
||||
FOR_EACH_IMPELLER_GLES3_PROC(IMPELLER_PROC);
|
||||
FOR_EACH_IMPELLER_EXT_PROC(IMPELLER_PROC);
|
||||
|
||||
#undef IMPELLER_PROC
|
||||
|
||||
@ -174,19 +174,19 @@ struct RenderPassData {
|
||||
|
||||
if (auto color = TextureGLES::Cast(pass_data.color_attachment.get())) {
|
||||
if (!color->SetAsFramebufferAttachment(
|
||||
fbo, TextureGLES::AttachmentPoint::kColor0)) {
|
||||
GL_FRAMEBUFFER, fbo, TextureGLES::AttachmentPoint::kColor0)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (auto depth = TextureGLES::Cast(pass_data.depth_attachment.get())) {
|
||||
if (!depth->SetAsFramebufferAttachment(
|
||||
fbo, TextureGLES::AttachmentPoint::kDepth)) {
|
||||
GL_FRAMEBUFFER, fbo, TextureGLES::AttachmentPoint::kDepth)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (auto stencil = TextureGLES::Cast(pass_data.stencil_attachment.get())) {
|
||||
if (!stencil->SetAsFramebufferAttachment(
|
||||
fbo, TextureGLES::AttachmentPoint::kStencil)) {
|
||||
GL_FRAMEBUFFER, fbo, TextureGLES::AttachmentPoint::kStencil)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#include "impeller/renderer/backend/gles/formats_gles.h"
|
||||
#include "impeller/renderer/backend/gles/proc_table_gles.h"
|
||||
#include "impeller/renderer/backend/gles/texture_gles.h"
|
||||
#include "impeller/renderer/formats.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
@ -18,12 +19,29 @@ bool SamplerGLES::IsValid() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
static GLint ToParam(MinMagFilter filter) {
|
||||
switch (filter) {
|
||||
case MinMagFilter::kNearest:
|
||||
return GL_NEAREST;
|
||||
case MinMagFilter::kLinear:
|
||||
return GL_LINEAR;
|
||||
static GLint ToParam(MinMagFilter minmag_filter, MipFilter mip_filter) {
|
||||
switch (mip_filter) {
|
||||
case MipFilter::kNone:
|
||||
switch (minmag_filter) {
|
||||
case MinMagFilter::kNearest:
|
||||
return GL_NEAREST;
|
||||
case MinMagFilter::kLinear:
|
||||
return GL_LINEAR;
|
||||
}
|
||||
case MipFilter::kNearest:
|
||||
switch (minmag_filter) {
|
||||
case MinMagFilter::kNearest:
|
||||
return GL_NEAREST_MIPMAP_NEAREST;
|
||||
case MinMagFilter::kLinear:
|
||||
return GL_LINEAR_MIPMAP_NEAREST;
|
||||
}
|
||||
case MipFilter::kLinear:
|
||||
switch (minmag_filter) {
|
||||
case MinMagFilter::kNearest:
|
||||
return GL_NEAREST_MIPMAP_LINEAR;
|
||||
case MinMagFilter::kLinear:
|
||||
return GL_LINEAR_MIPMAP_LINEAR;
|
||||
}
|
||||
}
|
||||
FML_UNREACHABLE();
|
||||
}
|
||||
@ -54,9 +72,9 @@ bool SamplerGLES::ConfigureBoundTexture(const TextureGLES& texture,
|
||||
|
||||
const auto& desc = GetDescriptor();
|
||||
gl.TexParameteri(target.value(), GL_TEXTURE_MIN_FILTER,
|
||||
ToParam(desc.min_filter));
|
||||
ToParam(desc.min_filter, desc.mip_filter));
|
||||
gl.TexParameteri(target.value(), GL_TEXTURE_MAG_FILTER,
|
||||
ToParam(desc.mag_filter));
|
||||
ToParam(desc.mag_filter, MipFilter::kNone));
|
||||
gl.TexParameteri(target.value(), GL_TEXTURE_WRAP_S,
|
||||
ToAddressMode(desc.width_address_mode));
|
||||
gl.TexParameteri(target.value(), GL_TEXTURE_WRAP_T,
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
#include "impeller/base/config.h"
|
||||
#include "impeller/base/validation.h"
|
||||
#include "impeller/renderer/backend/gles/formats_gles.h"
|
||||
#include "impeller/renderer/formats.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
@ -349,11 +350,15 @@ void TextureGLES::InitializeContentsIfNecessary() const {
|
||||
}
|
||||
}
|
||||
|
||||
bool TextureGLES::Bind() const {
|
||||
std::optional<GLuint> TextureGLES::GetGLHandle() const {
|
||||
if (!IsValid()) {
|
||||
return false;
|
||||
return std::nullopt;
|
||||
}
|
||||
auto handle = reactor_->GetGLHandle(handle_);
|
||||
return reactor_->GetGLHandle(handle_);
|
||||
}
|
||||
|
||||
bool TextureGLES::Bind() const {
|
||||
auto handle = GetGLHandle();
|
||||
if (!handle.has_value()) {
|
||||
return false;
|
||||
}
|
||||
@ -375,6 +380,37 @@ bool TextureGLES::Bind() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TextureGLES::GenerateMipmaps() const {
|
||||
if (!IsValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto type = GetTextureDescriptor().type;
|
||||
switch (type) {
|
||||
case TextureType::kTexture2D:
|
||||
break;
|
||||
case TextureType::kTexture2DMultisample:
|
||||
VALIDATION_LOG << "Generating mipmaps for multisample textures is not "
|
||||
"supported in the GLES backend.";
|
||||
return false;
|
||||
case TextureType::kTextureCube:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!Bind()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto handle = GetGLHandle();
|
||||
if (!handle.has_value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& gl = reactor_->GetProcTable();
|
||||
gl.GenerateMipmap(ToTextureType(type));
|
||||
return true;
|
||||
}
|
||||
|
||||
TextureGLES::Type TextureGLES::GetType() const {
|
||||
return type_;
|
||||
}
|
||||
@ -390,20 +426,21 @@ static GLenum ToAttachmentPoint(TextureGLES::AttachmentPoint point) {
|
||||
}
|
||||
}
|
||||
|
||||
bool TextureGLES::SetAsFramebufferAttachment(GLuint fbo,
|
||||
bool TextureGLES::SetAsFramebufferAttachment(GLenum target,
|
||||
GLuint fbo,
|
||||
AttachmentPoint point) const {
|
||||
if (!IsValid()) {
|
||||
return false;
|
||||
}
|
||||
InitializeContentsIfNecessary();
|
||||
auto handle = reactor_->GetGLHandle(handle_);
|
||||
auto handle = GetGLHandle();
|
||||
if (!handle.has_value()) {
|
||||
return false;
|
||||
}
|
||||
const auto& gl = reactor_->GetProcTable();
|
||||
switch (type_) {
|
||||
case Type::kTexture:
|
||||
gl.FramebufferTexture2D(GL_FRAMEBUFFER, // target
|
||||
gl.FramebufferTexture2D(target, // target
|
||||
ToAttachmentPoint(point), // attachment
|
||||
GL_TEXTURE_2D, // textarget
|
||||
handle.value(), // texture
|
||||
@ -411,7 +448,7 @@ bool TextureGLES::SetAsFramebufferAttachment(GLuint fbo,
|
||||
);
|
||||
break;
|
||||
case Type::kRenderBuffer:
|
||||
gl.FramebufferRenderbuffer(GL_FRAMEBUFFER, // target
|
||||
gl.FramebufferRenderbuffer(target, // target
|
||||
ToAttachmentPoint(point), // attachment
|
||||
GL_RENDERBUFFER, // render-buffer target
|
||||
handle.value() // render-buffer
|
||||
|
||||
@ -33,14 +33,19 @@ class TextureGLES final : public Texture,
|
||||
// |Texture|
|
||||
~TextureGLES() override;
|
||||
|
||||
std::optional<GLuint> GetGLHandle() const;
|
||||
|
||||
[[nodiscard]] bool Bind() const;
|
||||
|
||||
[[nodiscard]] bool GenerateMipmaps() const;
|
||||
|
||||
enum class AttachmentPoint {
|
||||
kColor0,
|
||||
kDepth,
|
||||
kStencil,
|
||||
};
|
||||
[[nodiscard]] bool SetAsFramebufferAttachment(GLuint fbo,
|
||||
[[nodiscard]] bool SetAsFramebufferAttachment(GLenum target,
|
||||
GLuint fbo,
|
||||
AttachmentPoint point) const;
|
||||
|
||||
Type GetType() const;
|
||||
|
||||
@ -8,6 +8,10 @@ impeller_component("metal") {
|
||||
sources = [
|
||||
"allocator_mtl.h",
|
||||
"allocator_mtl.mm",
|
||||
"blit_command_mtl.h",
|
||||
"blit_command_mtl.mm",
|
||||
"blit_pass_mtl.h",
|
||||
"blit_pass_mtl.mm",
|
||||
"command_buffer_mtl.h",
|
||||
"command_buffer_mtl.mm",
|
||||
"context_mtl.h",
|
||||
|
||||
@ -0,0 +1,43 @@
|
||||
// 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 <Metal/Metal.h>
|
||||
|
||||
#include "impeller/base/backend_cast.h"
|
||||
#include "impeller/renderer/blit_command.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
/// Mixin for dispatching Metal commands.
|
||||
struct BlitEncodeMTL : BackendCast<BlitEncodeMTL, BlitCommand> {
|
||||
virtual ~BlitEncodeMTL();
|
||||
|
||||
virtual std::string GetLabel() const = 0;
|
||||
|
||||
[[nodiscard]] virtual bool Encode(
|
||||
id<MTLBlitCommandEncoder> encoder) const = 0;
|
||||
};
|
||||
|
||||
struct BlitCopyTextureToTextureCommandMTL
|
||||
: public BlitCopyTextureToTextureCommand,
|
||||
public BlitEncodeMTL {
|
||||
~BlitCopyTextureToTextureCommandMTL() override;
|
||||
|
||||
std::string GetLabel() const override;
|
||||
|
||||
[[nodiscard]] bool Encode(id<MTLBlitCommandEncoder> encoder) const override;
|
||||
};
|
||||
|
||||
struct BlitGenerateMipmapCommandMTL : public BlitGenerateMipmapCommand,
|
||||
public BlitEncodeMTL {
|
||||
~BlitGenerateMipmapCommandMTL() override;
|
||||
|
||||
std::string GetLabel() const override;
|
||||
|
||||
[[nodiscard]] bool Encode(id<MTLBlitCommandEncoder> encoder) const override;
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
@ -0,0 +1,70 @@
|
||||
// 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/metal/blit_command_mtl.h"
|
||||
|
||||
#include "impeller/renderer/backend/metal/texture_mtl.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
BlitEncodeMTL::~BlitEncodeMTL() = default;
|
||||
|
||||
BlitCopyTextureToTextureCommandMTL::~BlitCopyTextureToTextureCommandMTL() =
|
||||
default;
|
||||
|
||||
std::string BlitCopyTextureToTextureCommandMTL::GetLabel() const {
|
||||
return label;
|
||||
}
|
||||
|
||||
bool BlitCopyTextureToTextureCommandMTL::Encode(
|
||||
id<MTLBlitCommandEncoder> encoder) const {
|
||||
auto source_mtl = TextureMTL::Cast(*source).GetMTLTexture();
|
||||
if (!source_mtl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto destination_mtl = TextureMTL::Cast(*destination).GetMTLTexture();
|
||||
if (!destination_mtl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto source_origin_mtl =
|
||||
MTLOriginMake(source_region.origin.x, source_region.origin.y, 0);
|
||||
auto source_size_mtl =
|
||||
MTLSizeMake(source_region.size.width, source_region.size.height, 1);
|
||||
auto destination_origin_mtl =
|
||||
MTLOriginMake(destination_origin.x, destination_origin.y, 0);
|
||||
|
||||
[encoder copyFromTexture:source_mtl
|
||||
sourceSlice:0
|
||||
sourceLevel:0
|
||||
sourceOrigin:source_origin_mtl
|
||||
sourceSize:source_size_mtl
|
||||
toTexture:destination_mtl
|
||||
destinationSlice:0
|
||||
destinationLevel:0
|
||||
destinationOrigin:destination_origin_mtl];
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
BlitGenerateMipmapCommandMTL::~BlitGenerateMipmapCommandMTL() = default;
|
||||
|
||||
std::string BlitGenerateMipmapCommandMTL::GetLabel() const {
|
||||
return label;
|
||||
}
|
||||
|
||||
bool BlitGenerateMipmapCommandMTL::Encode(
|
||||
id<MTLBlitCommandEncoder> encoder) const {
|
||||
auto texture_mtl = TextureMTL::Cast(*texture).GetMTLTexture();
|
||||
if (!texture_mtl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
[encoder generateMipmapsForTexture:texture_mtl];
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
@ -0,0 +1,56 @@
|
||||
// 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 <Metal/Metal.h>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/renderer/backend/metal/blit_command_mtl.h"
|
||||
#include "impeller/renderer/blit_pass.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
class BlitPassMTL final : public BlitPass {
|
||||
public:
|
||||
// |RenderPass|
|
||||
~BlitPassMTL() override;
|
||||
|
||||
private:
|
||||
friend class CommandBufferMTL;
|
||||
|
||||
std::vector<std::unique_ptr<BlitEncodeMTL>> commands_;
|
||||
id<MTLCommandBuffer> buffer_ = nil;
|
||||
std::string label_;
|
||||
bool is_valid_ = false;
|
||||
|
||||
explicit BlitPassMTL(id<MTLCommandBuffer> buffer);
|
||||
|
||||
// |BlitPass|
|
||||
bool IsValid() const override;
|
||||
|
||||
// |BlitPass|
|
||||
void OnSetLabel(std::string label) override;
|
||||
|
||||
// |BlitPass|
|
||||
bool EncodeCommands(
|
||||
const std::shared_ptr<Allocator>& transients_allocator) const override;
|
||||
|
||||
bool EncodeCommands(id<MTLBlitCommandEncoder> pass) const;
|
||||
|
||||
// |BlitPass|
|
||||
void OnCopyTextureToTextureCommand(std::shared_ptr<Texture> source,
|
||||
std::shared_ptr<Texture> destination,
|
||||
IRect source_region,
|
||||
IPoint destination_origin,
|
||||
std::string label) override;
|
||||
|
||||
// |BlitPass|
|
||||
void OnGenerateMipmapCommand(std::shared_ptr<Texture> texture,
|
||||
std::string label) override;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(BlitPassMTL);
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
@ -0,0 +1,117 @@
|
||||
// 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/metal/blit_pass_mtl.h"
|
||||
#include <Metal/Metal.h>
|
||||
#include <memory>
|
||||
#include <variant>
|
||||
|
||||
#include "flutter/fml/closure.h"
|
||||
#include "flutter/fml/logging.h"
|
||||
#include "flutter/fml/trace_event.h"
|
||||
#include "impeller/base/backend_cast.h"
|
||||
#include "impeller/renderer/backend/metal/blit_command_mtl.h"
|
||||
#include "impeller/renderer/backend/metal/device_buffer_mtl.h"
|
||||
#include "impeller/renderer/backend/metal/formats_mtl.h"
|
||||
#include "impeller/renderer/backend/metal/pipeline_mtl.h"
|
||||
#include "impeller/renderer/backend/metal/sampler_mtl.h"
|
||||
#include "impeller/renderer/backend/metal/texture_mtl.h"
|
||||
#include "impeller/renderer/blit_command.h"
|
||||
#include "impeller/renderer/formats.h"
|
||||
#include "impeller/renderer/host_buffer.h"
|
||||
#include "impeller/renderer/shader_types.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
BlitPassMTL::BlitPassMTL(id<MTLCommandBuffer> buffer) : buffer_(buffer) {
|
||||
if (!buffer_) {
|
||||
return;
|
||||
}
|
||||
is_valid_ = true;
|
||||
}
|
||||
|
||||
BlitPassMTL::~BlitPassMTL() = default;
|
||||
|
||||
bool BlitPassMTL::IsValid() const {
|
||||
return is_valid_;
|
||||
}
|
||||
|
||||
void BlitPassMTL::OnSetLabel(std::string label) {
|
||||
if (label.empty()) {
|
||||
return;
|
||||
}
|
||||
label_ = std::move(label);
|
||||
}
|
||||
|
||||
bool BlitPassMTL::EncodeCommands(
|
||||
const std::shared_ptr<Allocator>& transients_allocator) const {
|
||||
TRACE_EVENT0("impeller", "BlitPassMTL::EncodeCommands");
|
||||
if (!IsValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto blit_command_encoder = [buffer_ blitCommandEncoder];
|
||||
|
||||
if (!blit_command_encoder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!label_.empty()) {
|
||||
[blit_command_encoder setLabel:@(label_.c_str())];
|
||||
}
|
||||
|
||||
// Success or failure, the pass must end. The buffer can only process one pass
|
||||
// at a time.
|
||||
fml::ScopedCleanupClosure auto_end(
|
||||
[blit_command_encoder]() { [blit_command_encoder endEncoding]; });
|
||||
|
||||
return EncodeCommands(blit_command_encoder);
|
||||
}
|
||||
|
||||
bool BlitPassMTL::EncodeCommands(id<MTLBlitCommandEncoder> encoder) const {
|
||||
fml::closure pop_debug_marker = [encoder]() { [encoder popDebugGroup]; };
|
||||
for (const auto& command : commands_) {
|
||||
fml::ScopedCleanupClosure auto_pop_debug_marker(pop_debug_marker);
|
||||
auto label = command->GetLabel();
|
||||
if (!label.empty()) {
|
||||
[encoder pushDebugGroup:@(label.c_str())];
|
||||
} else {
|
||||
auto_pop_debug_marker.Release();
|
||||
}
|
||||
|
||||
if (command->Encode(encoder)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// |BlitPass|
|
||||
void BlitPassMTL::OnCopyTextureToTextureCommand(
|
||||
std::shared_ptr<Texture> source,
|
||||
std::shared_ptr<Texture> destination,
|
||||
IRect source_region,
|
||||
IPoint destination_origin,
|
||||
std::string label) {
|
||||
auto command = std::make_unique<BlitCopyTextureToTextureCommandMTL>();
|
||||
command->label = label;
|
||||
command->source = std::move(source);
|
||||
command->destination = std::move(destination);
|
||||
command->source_region = source_region;
|
||||
command->destination_origin = destination_origin;
|
||||
|
||||
commands_.emplace_back(std::move(command));
|
||||
}
|
||||
|
||||
// |BlitPass|
|
||||
void BlitPassMTL::OnGenerateMipmapCommand(std::shared_ptr<Texture> texture,
|
||||
std::string label) {
|
||||
auto command = std::make_unique<BlitGenerateMipmapCommandMTL>();
|
||||
command->label = label;
|
||||
command->texture = std::move(texture);
|
||||
|
||||
commands_.emplace_back(std::move(command));
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
@ -38,6 +38,9 @@ class CommandBufferMTL final : public CommandBuffer {
|
||||
std::shared_ptr<RenderPass> OnCreateRenderPass(
|
||||
RenderTarget target) const override;
|
||||
|
||||
// |CommandBuffer|
|
||||
std::shared_ptr<BlitPass> OnCreateBlitPass() const override;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(CommandBufferMTL);
|
||||
};
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
#include "impeller/renderer/backend/metal/command_buffer_mtl.h"
|
||||
|
||||
#include "impeller/renderer/backend/metal/blit_pass_mtl.h"
|
||||
#include "impeller/renderer/backend/metal/render_pass_mtl.h"
|
||||
|
||||
namespace impeller {
|
||||
@ -202,4 +203,17 @@ std::shared_ptr<RenderPass> CommandBufferMTL::OnCreateRenderPass(
|
||||
return pass;
|
||||
}
|
||||
|
||||
std::shared_ptr<BlitPass> CommandBufferMTL::OnCreateBlitPass() const {
|
||||
if (!buffer_) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto pass = std::shared_ptr<BlitPassMTL>(new BlitPassMTL(buffer_));
|
||||
if (!pass->IsValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return pass;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@ -275,6 +275,18 @@ constexpr MTLSamplerMinMagFilter ToMTLSamplerMinMagFilter(MinMagFilter filter) {
|
||||
return MTLSamplerMinMagFilterNearest;
|
||||
}
|
||||
|
||||
constexpr MTLSamplerMipFilter ToMTLSamplerMipFilter(MipFilter filter) {
|
||||
switch (filter) {
|
||||
case MipFilter::kNone:
|
||||
return MTLSamplerMipFilterNotMipmapped;
|
||||
case MipFilter::kNearest:
|
||||
return MTLSamplerMipFilterNearest;
|
||||
case MipFilter::kLinear:
|
||||
return MTLSamplerMipFilterLinear;
|
||||
}
|
||||
return MTLSamplerMipFilterNotMipmapped;
|
||||
}
|
||||
|
||||
constexpr MTLSamplerAddressMode ToMTLSamplerAddressMode(
|
||||
SamplerAddressMode mode) {
|
||||
switch (mode) {
|
||||
|
||||
@ -25,6 +25,7 @@ std::shared_ptr<const Sampler> SamplerLibraryMTL::GetSampler(
|
||||
auto desc = [[MTLSamplerDescriptor alloc] init];
|
||||
desc.minFilter = ToMTLSamplerMinMagFilter(descriptor.min_filter);
|
||||
desc.magFilter = ToMTLSamplerMinMagFilter(descriptor.mag_filter);
|
||||
desc.mipFilter = ToMTLSamplerMipFilter(descriptor.mip_filter);
|
||||
desc.sAddressMode = ToMTLSamplerAddressMode(descriptor.width_address_mode);
|
||||
desc.tAddressMode = ToMTLSamplerAddressMode(descriptor.height_address_mode);
|
||||
desc.rAddressMode = ToMTLSamplerAddressMode(descriptor.depth_address_mode);
|
||||
|
||||
@ -8,6 +8,8 @@ impeller_component("vulkan") {
|
||||
sources = [
|
||||
"allocator_vk.cc",
|
||||
"allocator_vk.h",
|
||||
"blit_pass_vk.cc",
|
||||
"blit_pass_vk.h",
|
||||
"capabilities_vk.cc",
|
||||
"capabilities_vk.h",
|
||||
"command_buffer_vk.cc",
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
// 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/blit_pass_vk.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
//
|
||||
|
||||
} // namespace impeller
|
||||
@ -0,0 +1,46 @@
|
||||
// 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/blit_pass.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
class BlitPassVK final : public BlitPass {
|
||||
public:
|
||||
// |BlitPass|
|
||||
~BlitPassVK() override;
|
||||
|
||||
private:
|
||||
friend class CommandBufferVK;
|
||||
|
||||
BlitPassVK();
|
||||
|
||||
// |BlitPass|
|
||||
bool IsValid() const override;
|
||||
|
||||
// |BlitPass|
|
||||
void OnSetLabel(std::string label) override;
|
||||
|
||||
// |BlitPass|
|
||||
bool EncodeCommands(
|
||||
const std::shared_ptr<Allocator>& transients_allocator) const override;
|
||||
|
||||
// |BlitPass|
|
||||
void OnCopyTextureToTextureCommand(std::shared_ptr<Texture> source,
|
||||
std::shared_ptr<Texture> destination,
|
||||
IRect source_region,
|
||||
IPoint destination_origin,
|
||||
std::string label) override;
|
||||
|
||||
// |BlitPass|
|
||||
void OnGenerateMipmapCommand(std::shared_ptr<Texture> texture,
|
||||
std::string label) override;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(BlitPassVK);
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
@ -30,4 +30,8 @@ std::shared_ptr<RenderPass> CommandBufferVK::OnCreateRenderPass(
|
||||
FML_UNREACHABLE();
|
||||
}
|
||||
|
||||
std::shared_ptr<BlitPass> CommandBufferVK::OnCreateBlitPass() const {
|
||||
FML_UNREACHABLE();
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@ -32,6 +32,9 @@ class CommandBufferVK final : public CommandBuffer {
|
||||
std::shared_ptr<RenderPass> OnCreateRenderPass(
|
||||
RenderTarget target) const override;
|
||||
|
||||
// |CommandBuffer|
|
||||
std::shared_ptr<BlitPass> OnCreateBlitPass() const override;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(CommandBufferVK);
|
||||
};
|
||||
|
||||
|
||||
11
engine/src/flutter/impeller/renderer/blit_command.cc
Normal file
11
engine/src/flutter/impeller/renderer/blit_command.cc
Normal file
@ -0,0 +1,11 @@
|
||||
// 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/blit_command.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
//
|
||||
|
||||
} // namespace impeller
|
||||
26
engine/src/flutter/impeller/renderer/blit_command.h
Normal file
26
engine/src/flutter/impeller/renderer/blit_command.h
Normal file
@ -0,0 +1,26 @@
|
||||
// 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 "impeller/renderer/texture.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
struct BlitCommand {
|
||||
std::string label;
|
||||
};
|
||||
|
||||
struct BlitCopyTextureToTextureCommand : public BlitCommand {
|
||||
std::shared_ptr<Texture> source;
|
||||
std::shared_ptr<Texture> destination;
|
||||
IRect source_region;
|
||||
IPoint destination_origin;
|
||||
};
|
||||
|
||||
struct BlitGenerateMipmapCommand : public BlitCommand {
|
||||
std::shared_ptr<Texture> texture;
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
91
engine/src/flutter/impeller/renderer/blit_pass.cc
Normal file
91
engine/src/flutter/impeller/renderer/blit_pass.cc
Normal file
@ -0,0 +1,91 @@
|
||||
// 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/blit_pass.h"
|
||||
#include <memory>
|
||||
|
||||
#include "impeller/base/strings.h"
|
||||
#include "impeller/base/validation.h"
|
||||
#include "impeller/renderer/blit_command.h"
|
||||
#include "impeller/renderer/host_buffer.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
BlitPass::BlitPass() : transients_buffer_(HostBuffer::Create()) {}
|
||||
|
||||
BlitPass::~BlitPass() = default;
|
||||
|
||||
HostBuffer& BlitPass::GetTransientsBuffer() {
|
||||
return *transients_buffer_;
|
||||
}
|
||||
|
||||
void BlitPass::SetLabel(std::string label) {
|
||||
if (label.empty()) {
|
||||
return;
|
||||
}
|
||||
transients_buffer_->SetLabel(SPrintF("%s Transients", label.c_str()));
|
||||
OnSetLabel(std::move(label));
|
||||
}
|
||||
|
||||
bool BlitPass::AddCopy(std::shared_ptr<Texture> source,
|
||||
std::shared_ptr<Texture> destination,
|
||||
std::optional<IRect> source_region,
|
||||
IPoint destination_origin,
|
||||
std::string label) {
|
||||
if (!source) {
|
||||
VALIDATION_LOG << "Attempted to add a texture blit with no source.";
|
||||
return false;
|
||||
}
|
||||
if (!destination) {
|
||||
VALIDATION_LOG << "Attempted to add a texture blit with no destination.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (source->GetTextureDescriptor().sample_count !=
|
||||
destination->GetTextureDescriptor().sample_count) {
|
||||
VALIDATION_LOG << SPrintF(
|
||||
"The source sample count (%d) must match the destination sample count "
|
||||
"(%d) for blits.",
|
||||
source->GetTextureDescriptor().sample_count,
|
||||
destination->GetTextureDescriptor().sample_count);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!source_region.has_value()) {
|
||||
source_region = IRect::MakeSize(source->GetSize());
|
||||
}
|
||||
|
||||
// Clip the source image.
|
||||
source_region =
|
||||
source_region->Intersection(IRect::MakeSize(source->GetSize()));
|
||||
if (!source_region.has_value()) {
|
||||
return true; // Nothing to blit.
|
||||
}
|
||||
|
||||
// Clip the destination image.
|
||||
source_region = source_region->Intersection(
|
||||
IRect(-destination_origin, destination->GetSize()));
|
||||
if (!source_region.has_value()) {
|
||||
return true; // Nothing to blit.
|
||||
}
|
||||
|
||||
OnCopyTextureToTextureCommand(std::move(source), std::move(destination),
|
||||
source_region.value(), destination_origin,
|
||||
label);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BlitPass::GenerateMipmap(std::shared_ptr<Texture> texture,
|
||||
std::string label) {
|
||||
if (!texture) {
|
||||
VALIDATION_LOG << "Attempted to add an invalid mipmap generation command "
|
||||
"with no texture.";
|
||||
return false;
|
||||
}
|
||||
|
||||
OnGenerateMipmapCommand(std::move(texture), label);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
105
engine/src/flutter/impeller/renderer/blit_pass.h
Normal file
105
engine/src/flutter/impeller/renderer/blit_pass.h
Normal file
@ -0,0 +1,105 @@
|
||||
// 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 <string>
|
||||
#include <variant>
|
||||
|
||||
#include "impeller/renderer/blit_command.h"
|
||||
#include "impeller/renderer/texture.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
class HostBuffer;
|
||||
class Allocator;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @brief Blit passes encode blit into the underlying command buffer.
|
||||
///
|
||||
/// Blit passes can be obtained from the command buffer in which
|
||||
/// the pass is meant to encode commands into.
|
||||
///
|
||||
/// @see `CommandBuffer`
|
||||
///
|
||||
class BlitPass {
|
||||
public:
|
||||
virtual ~BlitPass();
|
||||
|
||||
virtual bool IsValid() const = 0;
|
||||
|
||||
void SetLabel(std::string label);
|
||||
|
||||
HostBuffer& GetTransientsBuffer();
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Record a command to copy the contents of one texture to
|
||||
/// another texture. The blit area is limited by the intersection
|
||||
/// of the texture coverage with respect the source region and
|
||||
/// destination origin.
|
||||
/// No work is encoded into the command buffer at this time.
|
||||
///
|
||||
/// @param[in] source The texture to read for copying.
|
||||
/// @param[in] destination The texture to overwrite using the source
|
||||
/// contents.
|
||||
/// @param[in] source_region The optional region of the source texture
|
||||
/// to use for copying. If not specified, the
|
||||
/// full size of the source texture is used.
|
||||
/// @param[in] destination_origin The origin to start writing to in the
|
||||
/// destination texture.
|
||||
/// @param[in] label The optional debug label to give the
|
||||
/// command.
|
||||
///
|
||||
/// @return If the command was valid for subsequent commitment.
|
||||
///
|
||||
bool AddCopy(std::shared_ptr<Texture> source,
|
||||
std::shared_ptr<Texture> destination,
|
||||
std::optional<IRect> source_region = std::nullopt,
|
||||
IPoint destination_origin = {},
|
||||
std::string label = "");
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Record a command to generate all mip levels for a texture.
|
||||
/// No work is encoded into the command buffer at this time.
|
||||
///
|
||||
/// @param[in] texture The texture to generate mipmaps for.
|
||||
/// @param[in] label The optional debug label to give the command.
|
||||
///
|
||||
/// @return If the command was valid for subsequent commitment.
|
||||
///
|
||||
bool GenerateMipmap(std::shared_ptr<Texture> texture, std::string label = "");
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Encode the recorded commands to the underlying command buffer.
|
||||
///
|
||||
/// @param transients_allocator The transients allocator.
|
||||
///
|
||||
/// @return If the commands were encoded to the underlying command
|
||||
/// buffer.
|
||||
///
|
||||
virtual bool EncodeCommands(
|
||||
const std::shared_ptr<Allocator>& transients_allocator) const = 0;
|
||||
|
||||
protected:
|
||||
std::shared_ptr<HostBuffer> transients_buffer_;
|
||||
|
||||
explicit BlitPass();
|
||||
|
||||
virtual void OnSetLabel(std::string label) = 0;
|
||||
|
||||
virtual void OnCopyTextureToTextureCommand(
|
||||
std::shared_ptr<Texture> source,
|
||||
std::shared_ptr<Texture> destination,
|
||||
IRect source_region,
|
||||
IPoint destination_origin,
|
||||
std::string label) = 0;
|
||||
|
||||
virtual void OnGenerateMipmapCommand(std::shared_ptr<Texture> texture,
|
||||
std::string label) = 0;
|
||||
|
||||
private:
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(BlitPass);
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
@ -27,4 +27,13 @@ std::shared_ptr<RenderPass> CommandBuffer::CreateRenderPass(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<BlitPass> CommandBuffer::CreateBlitPass() const {
|
||||
auto pass = OnCreateBlitPass();
|
||||
if (pass && pass->IsValid()) {
|
||||
pass->SetLabel("BlitPass");
|
||||
return pass;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/renderer/blit_pass.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
@ -65,20 +66,29 @@ class CommandBuffer {
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Create a render pass to record render commands into.
|
||||
///
|
||||
/// @param[in] desc The description of the render target this pass will
|
||||
/// target.
|
||||
/// @param[in] render_target The description of the render target this pass
|
||||
/// will target.
|
||||
///
|
||||
/// @return A valid render pass or null.
|
||||
///
|
||||
std::shared_ptr<RenderPass> CreateRenderPass(
|
||||
RenderTarget render_target) const;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Create a blit pass to record blit commands into.
|
||||
///
|
||||
/// @return A valid blit pass or null.
|
||||
///
|
||||
std::shared_ptr<BlitPass> CreateBlitPass() const;
|
||||
|
||||
protected:
|
||||
CommandBuffer();
|
||||
|
||||
virtual std::shared_ptr<RenderPass> OnCreateRenderPass(
|
||||
RenderTarget render_target) const = 0;
|
||||
|
||||
virtual std::shared_ptr<BlitPass> OnCreateBlitPass() const = 0;
|
||||
|
||||
private:
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(CommandBuffer);
|
||||
};
|
||||
|
||||
@ -199,6 +199,16 @@ enum class MinMagFilter {
|
||||
kLinear,
|
||||
};
|
||||
|
||||
enum class MipFilter {
|
||||
/// Always sample from mip level 0. Other mip levels are ignored.
|
||||
kNone,
|
||||
/// Sample from the nearest mip level.
|
||||
kNearest,
|
||||
/// Sample from the two nearest mip levels and linearly interpolate between
|
||||
/// them.
|
||||
kLinear,
|
||||
};
|
||||
|
||||
enum class SamplerAddressMode {
|
||||
kClampToEdge,
|
||||
kRepeat,
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
#include "flutter/fml/time/time_point.h"
|
||||
#include "flutter/testing/testing.h"
|
||||
#include "impeller/base/strings.h"
|
||||
#include "impeller/fixtures/box_fade.frag.h"
|
||||
#include "impeller/fixtures/box_fade.vert.h"
|
||||
#include "impeller/fixtures/colors.frag.h"
|
||||
@ -12,6 +13,8 @@
|
||||
#include "impeller/fixtures/impeller.vert.h"
|
||||
#include "impeller/fixtures/instanced_draw.frag.h"
|
||||
#include "impeller/fixtures/instanced_draw.vert.h"
|
||||
#include "impeller/fixtures/mipmaps.frag.h"
|
||||
#include "impeller/fixtures/mipmaps.vert.h"
|
||||
#include "impeller/fixtures/test_texture.frag.h"
|
||||
#include "impeller/fixtures/test_texture.vert.h"
|
||||
#include "impeller/geometry/path_builder.h"
|
||||
@ -442,6 +445,237 @@ TEST_P(RendererTest, CanRenderInstanced) {
|
||||
}
|
||||
#endif // IMPELLER_ENABLE_METAL
|
||||
|
||||
TEST_P(RendererTest, CanBlitTextureToTexture) {
|
||||
auto context = GetContext();
|
||||
ASSERT_TRUE(context);
|
||||
|
||||
using VS = MipmapsVertexShader;
|
||||
using FS = MipmapsFragmentShader;
|
||||
auto desc = PipelineBuilder<VS, FS>::MakeDefaultPipelineDescriptor(*context);
|
||||
ASSERT_TRUE(desc.has_value());
|
||||
desc->SetSampleCount(SampleCount::kCount4);
|
||||
auto mipmaps_pipeline =
|
||||
context->GetPipelineLibrary()->GetRenderPipeline(std::move(desc)).get();
|
||||
ASSERT_TRUE(mipmaps_pipeline);
|
||||
|
||||
TextureDescriptor texture_desc;
|
||||
texture_desc.format = PixelFormat::kR8G8B8A8UNormInt;
|
||||
texture_desc.size = {800, 600};
|
||||
texture_desc.mip_count = 1u;
|
||||
texture_desc.usage =
|
||||
static_cast<TextureUsageMask>(TextureUsage::kRenderTarget) |
|
||||
static_cast<TextureUsageMask>(TextureUsage::kShaderRead);
|
||||
auto texture = context->GetPermanentsAllocator()->CreateTexture(
|
||||
StorageMode::kHostVisible, texture_desc);
|
||||
ASSERT_TRUE(texture);
|
||||
|
||||
auto bridge = CreateTextureForFixture("bay_bridge.jpg");
|
||||
auto boston = CreateTextureForFixture("boston.jpg");
|
||||
ASSERT_TRUE(bridge && boston);
|
||||
auto sampler = context->GetSamplerLibrary()->GetSampler({});
|
||||
ASSERT_TRUE(sampler);
|
||||
|
||||
// Vertex buffer.
|
||||
VertexBufferBuilder<VS::PerVertexData> vertex_builder;
|
||||
vertex_builder.SetLabel("Box");
|
||||
auto size = Point(boston->GetSize());
|
||||
vertex_builder.AddVertices({
|
||||
{{0, 0}, {0.0, 0.0}}, // 1
|
||||
{{size.x, 0}, {1.0, 0.0}}, // 2
|
||||
{{size.x, size.y}, {1.0, 1.0}}, // 3
|
||||
{{0, 0}, {0.0, 0.0}}, // 1
|
||||
{{size.x, size.y}, {1.0, 1.0}}, // 3
|
||||
{{0, size.y}, {0.0, 1.0}}, // 4
|
||||
});
|
||||
auto vertex_buffer =
|
||||
vertex_builder.CreateVertexBuffer(*context->GetTransientsAllocator());
|
||||
ASSERT_TRUE(vertex_buffer);
|
||||
|
||||
Renderer::RenderCallback callback = [&](RenderTarget& render_target) {
|
||||
auto buffer = context->CreateRenderCommandBuffer();
|
||||
if (!buffer) {
|
||||
return false;
|
||||
}
|
||||
buffer->SetLabel("Playground Command Buffer");
|
||||
|
||||
{
|
||||
auto pass = buffer->CreateBlitPass();
|
||||
if (!pass) {
|
||||
return false;
|
||||
}
|
||||
pass->SetLabel("Playground Blit Pass");
|
||||
|
||||
if (render_target.GetColorAttachments().empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Blit `bridge` to the top left corner of the texture.
|
||||
pass->AddCopy(bridge, texture);
|
||||
|
||||
pass->EncodeCommands(context->GetTransientsAllocator());
|
||||
}
|
||||
|
||||
{
|
||||
auto pass = buffer->CreateRenderPass(render_target);
|
||||
if (!pass) {
|
||||
return false;
|
||||
}
|
||||
pass->SetLabel("Playground Render Pass");
|
||||
{
|
||||
Command cmd;
|
||||
cmd.label = "Image";
|
||||
cmd.pipeline = mipmaps_pipeline;
|
||||
|
||||
cmd.BindVertices(vertex_buffer);
|
||||
|
||||
VS::VertInfo vert_info;
|
||||
vert_info.mvp = Matrix::MakeOrthographic(pass->GetRenderTargetSize()) *
|
||||
Matrix::MakeScale(GetContentScale());
|
||||
VS::BindVertInfo(cmd,
|
||||
pass->GetTransientsBuffer().EmplaceUniform(vert_info));
|
||||
|
||||
FS::FragInfo frag_info;
|
||||
frag_info.lod = 0;
|
||||
FS::BindFragInfo(cmd,
|
||||
pass->GetTransientsBuffer().EmplaceUniform(frag_info));
|
||||
|
||||
auto sampler = context->GetSamplerLibrary()->GetSampler({});
|
||||
FS::BindTex(cmd, texture, sampler);
|
||||
|
||||
pass->AddCommand(std::move(cmd));
|
||||
}
|
||||
pass->EncodeCommands(context->GetTransientsAllocator());
|
||||
}
|
||||
|
||||
if (!buffer->SubmitCommands()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
OpenPlaygroundHere(callback);
|
||||
}
|
||||
|
||||
TEST_P(RendererTest, CanGenerateMipmaps) {
|
||||
auto context = GetContext();
|
||||
ASSERT_TRUE(context);
|
||||
|
||||
using VS = MipmapsVertexShader;
|
||||
using FS = MipmapsFragmentShader;
|
||||
auto desc = PipelineBuilder<VS, FS>::MakeDefaultPipelineDescriptor(*context);
|
||||
ASSERT_TRUE(desc.has_value());
|
||||
desc->SetSampleCount(SampleCount::kCount4);
|
||||
auto mipmaps_pipeline =
|
||||
context->GetPipelineLibrary()->GetRenderPipeline(std::move(desc)).get();
|
||||
ASSERT_TRUE(mipmaps_pipeline);
|
||||
|
||||
auto boston = CreateTextureForFixture("boston.jpg", true);
|
||||
ASSERT_TRUE(boston);
|
||||
|
||||
// Vertex buffer.
|
||||
VertexBufferBuilder<VS::PerVertexData> vertex_builder;
|
||||
vertex_builder.SetLabel("Box");
|
||||
auto size = Point(boston->GetSize());
|
||||
vertex_builder.AddVertices({
|
||||
{{0, 0}, {0.0, 0.0}}, // 1
|
||||
{{size.x, 0}, {1.0, 0.0}}, // 2
|
||||
{{size.x, size.y}, {1.0, 1.0}}, // 3
|
||||
{{0, 0}, {0.0, 0.0}}, // 1
|
||||
{{size.x, size.y}, {1.0, 1.0}}, // 3
|
||||
{{0, size.y}, {0.0, 1.0}}, // 4
|
||||
});
|
||||
auto vertex_buffer =
|
||||
vertex_builder.CreateVertexBuffer(*context->GetPermanentsAllocator());
|
||||
ASSERT_TRUE(vertex_buffer);
|
||||
|
||||
bool first_frame = true;
|
||||
Renderer::RenderCallback callback = [&](RenderTarget& render_target) {
|
||||
if (first_frame) {
|
||||
ImGui::SetNextWindowPos({10, 10});
|
||||
}
|
||||
|
||||
const char* mip_filter_names[] = {"None", "Nearest", "Linear"};
|
||||
const MipFilter mip_filters[] = {MipFilter::kNone, MipFilter::kNearest,
|
||||
MipFilter::kLinear};
|
||||
const char* min_filter_names[] = {"Nearest", "Linear"};
|
||||
const MinMagFilter min_filters[] = {MinMagFilter::kNearest,
|
||||
MinMagFilter::kLinear};
|
||||
|
||||
// UI state.
|
||||
static int selected_mip_filter = 2;
|
||||
static int selected_min_filter = 0;
|
||||
static float lod = 4.5;
|
||||
|
||||
ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
|
||||
ImGui::Combo("Mip filter", &selected_mip_filter, mip_filter_names,
|
||||
sizeof(mip_filter_names) / sizeof(char*));
|
||||
ImGui::Combo("Min filter", &selected_min_filter, min_filter_names,
|
||||
sizeof(min_filter_names) / sizeof(char*));
|
||||
ImGui::SliderFloat("LOD", &lod, 0, boston->GetMipCount() - 1);
|
||||
ImGui::End();
|
||||
|
||||
auto buffer = context->CreateRenderCommandBuffer();
|
||||
if (!buffer) {
|
||||
return false;
|
||||
}
|
||||
buffer->SetLabel("Playground Command Buffer");
|
||||
|
||||
if (first_frame) {
|
||||
auto pass = buffer->CreateBlitPass();
|
||||
if (!pass) {
|
||||
return false;
|
||||
}
|
||||
pass->SetLabel("Playground Blit Pass");
|
||||
|
||||
pass->GenerateMipmap(boston, "Boston Mipmap");
|
||||
|
||||
pass->EncodeCommands(context->GetTransientsAllocator());
|
||||
}
|
||||
|
||||
first_frame = false;
|
||||
|
||||
{
|
||||
auto pass = buffer->CreateRenderPass(render_target);
|
||||
if (!pass) {
|
||||
return false;
|
||||
}
|
||||
pass->SetLabel("Playground Render Pass");
|
||||
{
|
||||
Command cmd;
|
||||
cmd.label = "Image LOD";
|
||||
cmd.pipeline = mipmaps_pipeline;
|
||||
|
||||
cmd.BindVertices(vertex_buffer);
|
||||
|
||||
VS::VertInfo vert_info;
|
||||
vert_info.mvp = Matrix::MakeOrthographic(pass->GetRenderTargetSize()) *
|
||||
Matrix::MakeScale(GetContentScale());
|
||||
VS::BindVertInfo(cmd,
|
||||
pass->GetTransientsBuffer().EmplaceUniform(vert_info));
|
||||
|
||||
FS::FragInfo frag_info;
|
||||
frag_info.lod = lod;
|
||||
FS::BindFragInfo(cmd,
|
||||
pass->GetTransientsBuffer().EmplaceUniform(frag_info));
|
||||
|
||||
SamplerDescriptor sampler_desc;
|
||||
sampler_desc.mip_filter = mip_filters[selected_mip_filter];
|
||||
sampler_desc.min_filter = min_filters[selected_min_filter];
|
||||
auto sampler = context->GetSamplerLibrary()->GetSampler(sampler_desc);
|
||||
FS::BindTex(cmd, boston, sampler);
|
||||
|
||||
pass->AddCommand(std::move(cmd));
|
||||
}
|
||||
pass->EncodeCommands(context->GetTransientsAllocator());
|
||||
}
|
||||
|
||||
if (!buffer->SubmitCommands()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
OpenPlaygroundHere(callback);
|
||||
}
|
||||
|
||||
TEST_P(RendererTest, TheImpeller) {
|
||||
using VS = ImpellerVertexShader;
|
||||
using FS = ImpellerFragmentShader;
|
||||
|
||||
@ -18,6 +18,7 @@ class Context;
|
||||
struct SamplerDescriptor final : public Comparable<SamplerDescriptor> {
|
||||
MinMagFilter min_filter = MinMagFilter::kNearest;
|
||||
MinMagFilter mag_filter = MinMagFilter::kNearest;
|
||||
MipFilter mip_filter = MipFilter::kNone;
|
||||
|
||||
SamplerAddressMode width_address_mode = SamplerAddressMode::kClampToEdge;
|
||||
SamplerAddressMode height_address_mode = SamplerAddressMode::kClampToEdge;
|
||||
@ -27,13 +28,15 @@ struct SamplerDescriptor final : public Comparable<SamplerDescriptor> {
|
||||
|
||||
// Comparable<SamplerDescriptor>
|
||||
std::size_t GetHash() const override {
|
||||
return fml::HashCombine(min_filter, mag_filter, width_address_mode,
|
||||
height_address_mode, depth_address_mode);
|
||||
return fml::HashCombine(min_filter, mag_filter, mip_filter,
|
||||
width_address_mode, height_address_mode,
|
||||
depth_address_mode);
|
||||
}
|
||||
|
||||
// Comparable<SamplerDescriptor>
|
||||
bool IsEqual(const SamplerDescriptor& o) const override {
|
||||
return min_filter == o.min_filter && mag_filter == o.mag_filter &&
|
||||
mip_filter == o.mip_filter &&
|
||||
width_address_mode == o.width_address_mode &&
|
||||
height_address_mode == o.height_address_mode &&
|
||||
depth_address_mode == o.depth_address_mode;
|
||||
|
||||
@ -42,6 +42,10 @@ bool Texture::SetContents(std::shared_ptr<const fml::Mapping> mapping,
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t Texture::GetMipCount() const {
|
||||
return GetTextureDescriptor().mip_count;
|
||||
}
|
||||
|
||||
const TextureDescriptor& Texture::GetTextureDescriptor() const {
|
||||
return desc_;
|
||||
}
|
||||
|
||||
@ -31,6 +31,8 @@ class Texture {
|
||||
|
||||
virtual ISize GetSize() const = 0;
|
||||
|
||||
size_t GetMipCount() const;
|
||||
|
||||
const TextureDescriptor& GetTextureDescriptor() const;
|
||||
|
||||
TextureIntent GetIntent() const;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user