mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[impeller] Add missing pieces to the OpenGLES backend. (flutter/engine#33223)
This commit is contained in:
parent
caf8268037
commit
eb4a892f0c
@ -78,6 +78,7 @@ bool ImGui_ImplImpeller_Init(std::shared_ptr<impeller::Context> context) {
|
||||
impeller::StorageMode::kHostVisible, texture_descriptor);
|
||||
IM_ASSERT(bd->font_texture != nullptr &&
|
||||
"Could not allocate ImGui font texture.");
|
||||
bd->font_texture->SetLabel("ImGui Font Texture");
|
||||
|
||||
[[maybe_unused]] bool uploaded = bd->font_texture->SetContents(
|
||||
pixels, texture_descriptor.GetByteSizeOfBaseMipLevel());
|
||||
|
||||
@ -203,6 +203,7 @@ bool Playground::OpenPlaygroundHere(Renderer::RenderCallback render_callback) {
|
||||
[]() { ImGui_ImplImpeller_Shutdown(); });
|
||||
|
||||
::glfwSetWindowSize(window, GetWindowSize().width, GetWindowSize().height);
|
||||
::glfwSetWindowPos(window, 200, 100);
|
||||
::glfwShowWindow(window);
|
||||
|
||||
while (true) {
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
#include "impeller/renderer/backend/gles/buffer_bindings_gles.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
#include "impeller/base/config.h"
|
||||
@ -21,7 +22,14 @@ BufferBindingsGLES::~BufferBindingsGLES() = default;
|
||||
|
||||
bool BufferBindingsGLES::RegisterVertexStageInput(
|
||||
const ProcTableGLES& gl,
|
||||
const std::vector<ShaderStageIOSlot>& inputs) {
|
||||
const std::vector<ShaderStageIOSlot>& p_inputs) {
|
||||
// Attrib locations have to be iterated over in order of location because we
|
||||
// will be calculating offsets later.
|
||||
auto inputs = p_inputs;
|
||||
std::sort(inputs.begin(), inputs.end(), [](const auto& lhs, const auto& rhs) {
|
||||
return lhs.location < rhs.location;
|
||||
});
|
||||
|
||||
std::vector<VertexAttribPointer> vertex_attrib_arrays;
|
||||
size_t offset = 0u;
|
||||
for (const auto& input : inputs) {
|
||||
|
||||
@ -21,7 +21,7 @@ DeviceBufferGLES::DeviceBufferGLES(ReactorGLES::Ref reactor,
|
||||
|
||||
// |DeviceBuffer|
|
||||
DeviceBufferGLES::~DeviceBufferGLES() {
|
||||
if (!reactor_) {
|
||||
if (!handle_.IsDead()) {
|
||||
reactor_->CollectHandle(handle_);
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,6 +21,8 @@ enum class HandleType {
|
||||
kTexture,
|
||||
kBuffer,
|
||||
kProgram,
|
||||
kRenderBuffer,
|
||||
kFrameBuffer,
|
||||
};
|
||||
|
||||
class ReactorGLES;
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "impeller/base/comparable.h"
|
||||
#include "impeller/base/validation.h"
|
||||
|
||||
namespace impeller {
|
||||
@ -43,6 +44,10 @@ ProcTableGLES::Resolver WrappedResolver(ProcTableGLES::Resolver resolver) {
|
||||
auto truncated = function.substr(0u, function.size() - 3);
|
||||
return resolver(truncated.c_str());
|
||||
}
|
||||
if (function.find("EXT", function.size() - 3) != std::string::npos) {
|
||||
auto truncated = function.substr(0u, function.size() - 3);
|
||||
return resolver(truncated.c_str());
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
}
|
||||
@ -95,6 +100,12 @@ ProcTableGLES::ProcTableGLES(Resolver resolver) {
|
||||
PushDebugGroupKHR.Reset();
|
||||
PopDebugGroupKHR.Reset();
|
||||
ObjectLabelKHR.Reset();
|
||||
} else {
|
||||
GetIntegerv(GL_MAX_LABEL_LENGTH_KHR, &debug_label_max_length_);
|
||||
}
|
||||
|
||||
if (!description_->HasExtension("GL_EXT_discard_framebuffer")) {
|
||||
DiscardFramebufferEXT.Reset();
|
||||
}
|
||||
|
||||
is_valid_ = true;
|
||||
@ -223,14 +234,17 @@ bool ProcTableGLES::IsCurrentFramebufferComplete() const {
|
||||
static std::optional<GLenum> ToDebugIdentifier(DebugResourceType type) {
|
||||
switch (type) {
|
||||
case DebugResourceType::kTexture:
|
||||
// No entry in GL_KHR_debug headers.
|
||||
return std::nullopt;
|
||||
return GL_TEXTURE;
|
||||
case DebugResourceType::kBuffer:
|
||||
return GL_BUFFER_KHR;
|
||||
case DebugResourceType::kProgram:
|
||||
return GL_PROGRAM_KHR;
|
||||
case DebugResourceType::kShader:
|
||||
return GL_SHADER_KHR;
|
||||
case DebugResourceType::kRenderBuffer:
|
||||
return GL_RENDERBUFFER;
|
||||
case DebugResourceType::kFrameBuffer:
|
||||
return GL_FRAMEBUFFER;
|
||||
}
|
||||
FML_UNREACHABLE();
|
||||
}
|
||||
@ -238,12 +252,12 @@ static std::optional<GLenum> ToDebugIdentifier(DebugResourceType type) {
|
||||
void ProcTableGLES::SetDebugLabel(DebugResourceType type,
|
||||
GLint name,
|
||||
const std::string& label) const {
|
||||
if (!ObjectLabelKHR.IsAvailable()) {
|
||||
if (debug_label_max_length_ <= 0) {
|
||||
return;
|
||||
}
|
||||
const auto identifier = ToDebugIdentifier(type);
|
||||
const auto label_length =
|
||||
std::min<GLsizei>(GL_MAX_LABEL_LENGTH_KHR - 1, label.size());
|
||||
std::min<GLsizei>(debug_label_max_length_ - 1, label.size());
|
||||
if (!identifier.has_value()) {
|
||||
return;
|
||||
}
|
||||
@ -254,4 +268,25 @@ void ProcTableGLES::SetDebugLabel(DebugResourceType type,
|
||||
);
|
||||
}
|
||||
|
||||
void ProcTableGLES::PushDebugGroup(const std::string& label) const {
|
||||
if (debug_label_max_length_ <= 0) {
|
||||
return;
|
||||
}
|
||||
UniqueID id;
|
||||
const auto label_length =
|
||||
std::min<GLsizei>(debug_label_max_length_ - 1, label.size());
|
||||
PushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION_KHR, // source
|
||||
static_cast<GLuint>(id.id), // id
|
||||
label_length, // length
|
||||
label.data() // message
|
||||
);
|
||||
}
|
||||
|
||||
void ProcTableGLES::PopDebugGroup() const {
|
||||
if (debug_label_max_length_ <= 0) {
|
||||
return;
|
||||
}
|
||||
PopDebugGroupKHR();
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@ -80,6 +80,8 @@ struct GLProc {
|
||||
PROC(AttachShader); \
|
||||
PROC(BindAttribLocation); \
|
||||
PROC(BindBuffer); \
|
||||
PROC(BindFramebuffer); \
|
||||
PROC(BindRenderbuffer); \
|
||||
PROC(BindTexture); \
|
||||
PROC(BlendEquationSeparate); \
|
||||
PROC(BlendFuncSeparate); \
|
||||
@ -95,7 +97,9 @@ struct GLProc {
|
||||
PROC(CreateShader); \
|
||||
PROC(CullFace); \
|
||||
PROC(DeleteBuffers); \
|
||||
PROC(DeleteFramebuffers); \
|
||||
PROC(DeleteProgram); \
|
||||
PROC(DeleteRenderbuffers); \
|
||||
PROC(DeleteShader); \
|
||||
PROC(DeleteTextures); \
|
||||
PROC(DepthFunc); \
|
||||
@ -107,8 +111,12 @@ struct GLProc {
|
||||
PROC(DrawElements); \
|
||||
PROC(Enable); \
|
||||
PROC(EnableVertexAttribArray); \
|
||||
PROC(FramebufferRenderbuffer); \
|
||||
PROC(FramebufferTexture2D); \
|
||||
PROC(FrontFace); \
|
||||
PROC(GenBuffers); \
|
||||
PROC(GenFramebuffers); \
|
||||
PROC(GenRenderbuffers); \
|
||||
PROC(GenTextures); \
|
||||
PROC(GetActiveUniform); \
|
||||
PROC(GetBooleanv); \
|
||||
@ -123,6 +131,7 @@ struct GLProc {
|
||||
PROC(IsFramebuffer); \
|
||||
PROC(IsProgram); \
|
||||
PROC(LinkProgram); \
|
||||
PROC(RenderbufferStorage); \
|
||||
PROC(Scissor); \
|
||||
PROC(ShaderBinary); \
|
||||
PROC(ShaderSource); \
|
||||
@ -141,6 +150,7 @@ struct GLProc {
|
||||
PROC(Viewport);
|
||||
|
||||
#define FOR_EACH_IMPELLER_EXT_PROC(PROC) \
|
||||
PROC(DiscardFramebufferEXT); \
|
||||
PROC(PushDebugGroupKHR); \
|
||||
PROC(PopDebugGroupKHR); \
|
||||
PROC(ObjectLabelKHR);
|
||||
@ -150,6 +160,8 @@ enum class DebugResourceType {
|
||||
kBuffer,
|
||||
kProgram,
|
||||
kShader,
|
||||
kRenderBuffer,
|
||||
kFrameBuffer,
|
||||
};
|
||||
|
||||
class ProcTableGLES {
|
||||
@ -181,9 +193,14 @@ class ProcTableGLES {
|
||||
GLint name,
|
||||
const std::string& label) const;
|
||||
|
||||
void PushDebugGroup(const std::string& string) const;
|
||||
|
||||
void PopDebugGroup() const;
|
||||
|
||||
private:
|
||||
bool is_valid_ = false;
|
||||
std::unique_ptr<GLDescription> description_;
|
||||
GLint debug_label_max_length_ = 0;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(ProcTableGLES);
|
||||
};
|
||||
|
||||
@ -66,6 +66,12 @@ static std::optional<GLuint> CreateGLHandle(const ProcTableGLES& gl,
|
||||
return handle;
|
||||
case HandleType::kProgram:
|
||||
return gl.CreateProgram();
|
||||
case HandleType::kRenderBuffer:
|
||||
gl.GenRenderbuffers(1u, &handle);
|
||||
return handle;
|
||||
case HandleType::kFrameBuffer:
|
||||
gl.GenFramebuffers(1u, &handle);
|
||||
return handle;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
@ -85,6 +91,12 @@ static bool CollectGLHandle(const ProcTableGLES& gl,
|
||||
case HandleType::kProgram:
|
||||
gl.DeleteProgram(handle);
|
||||
return true;
|
||||
case HandleType::kRenderBuffer:
|
||||
gl.DeleteRenderbuffers(1u, &handle);
|
||||
return true;
|
||||
case HandleType::kFrameBuffer:
|
||||
gl.DeleteFramebuffers(1u, &handle);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -135,6 +147,10 @@ static DebugResourceType ToDebugResourceType(HandleType type) {
|
||||
return DebugResourceType::kBuffer;
|
||||
case HandleType::kProgram:
|
||||
return DebugResourceType::kProgram;
|
||||
case HandleType::kRenderBuffer:
|
||||
return DebugResourceType::kRenderBuffer;
|
||||
case HandleType::kFrameBuffer:
|
||||
return DebugResourceType::kFrameBuffer;
|
||||
}
|
||||
FML_UNREACHABLE();
|
||||
}
|
||||
@ -213,6 +229,17 @@ void ReactorGLES::SetDebugLabel(const GLESHandle& handle, std::string label) {
|
||||
if (handle.IsDead()) {
|
||||
return;
|
||||
}
|
||||
if (in_reaction_) {
|
||||
if (auto found = live_gl_handles_.find(handle);
|
||||
found != live_gl_handles_.end() && found->second.has_value()) {
|
||||
GetProcTable().SetDebugLabel(
|
||||
ToDebugResourceType(found->first.type), // type
|
||||
found->second.value(), // name
|
||||
label // label
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
pending_debug_labels_[handle] = std::move(label);
|
||||
}
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
#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/texture_gles.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
@ -119,8 +120,9 @@ struct RenderPassData {
|
||||
uint32_t clear_stencil = 0u;
|
||||
Scalar clear_depth = 1.0;
|
||||
|
||||
bool has_depth_attachment = false;
|
||||
bool has_stencil_attachment = false;
|
||||
std::shared_ptr<Texture> color_attachment;
|
||||
std::shared_ptr<Texture> depth_attachment;
|
||||
std::shared_ptr<Texture> stencil_attachment;
|
||||
|
||||
bool clear_color_attachment = true;
|
||||
bool clear_depth_attachment = true;
|
||||
@ -129,6 +131,8 @@ struct RenderPassData {
|
||||
bool discard_color_attachment = true;
|
||||
bool discard_depth_attachment = true;
|
||||
bool discard_stencil_attachment = true;
|
||||
|
||||
std::string label;
|
||||
};
|
||||
|
||||
[[nodiscard]] bool EncodeCommandsInReactor(
|
||||
@ -138,17 +142,70 @@ struct RenderPassData {
|
||||
const std::vector<Command>& commands) {
|
||||
TRACE_EVENT0("impeller", __FUNCTION__);
|
||||
|
||||
if (commands.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto& gl = reactor.GetProcTable();
|
||||
|
||||
fml::ScopedCleanupClosure pop_pass_debug_marker(
|
||||
[&gl]() { gl.PopDebugGroup(); });
|
||||
if (!pass_data.label.empty()) {
|
||||
gl.PushDebugGroup(pass_data.label);
|
||||
} else {
|
||||
pop_pass_debug_marker.Release();
|
||||
}
|
||||
|
||||
GLuint fbo = GL_NONE;
|
||||
fml::ScopedCleanupClosure delete_fbo([&gl, &fbo]() {
|
||||
if (fbo != GL_NONE) {
|
||||
gl.BindFramebuffer(GL_FRAMEBUFFER, GL_NONE);
|
||||
gl.DeleteFramebuffers(1u, &fbo);
|
||||
}
|
||||
});
|
||||
|
||||
const auto is_default_fbo =
|
||||
TextureGLES::Cast(*pass_data.color_attachment).IsWrapped();
|
||||
|
||||
if (!is_default_fbo) {
|
||||
// Create and bind an offscreen FBO.
|
||||
gl.GenFramebuffers(1u, &fbo);
|
||||
gl.BindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
|
||||
if (auto color = TextureGLES::Cast(pass_data.color_attachment.get())) {
|
||||
if (!color->SetAsFramebufferAttachment(
|
||||
fbo, TextureGLES::AttachmentPoint::kColor0)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (auto depth = TextureGLES::Cast(pass_data.depth_attachment.get())) {
|
||||
if (!depth->SetAsFramebufferAttachment(
|
||||
fbo, TextureGLES::AttachmentPoint::kDepth)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (auto stencil = TextureGLES::Cast(pass_data.stencil_attachment.get())) {
|
||||
if (!stencil->SetAsFramebufferAttachment(
|
||||
fbo, TextureGLES::AttachmentPoint::kStencil)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (gl.CheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||
VALIDATION_LOG << "Could not create a complete frambuffer.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
gl.ClearColor(pass_data.clear_color.red, // red
|
||||
pass_data.clear_color.green, // green
|
||||
pass_data.clear_color.blue, // blue
|
||||
pass_data.clear_color.alpha // alpha
|
||||
);
|
||||
if (pass_data.has_depth_attachment) {
|
||||
if (pass_data.depth_attachment) {
|
||||
gl.ClearDepthf(pass_data.clear_depth);
|
||||
}
|
||||
if (pass_data.has_stencil_attachment) {
|
||||
if (pass_data.stencil_attachment) {
|
||||
gl.ClearStencil(pass_data.clear_stencil);
|
||||
}
|
||||
|
||||
@ -175,6 +232,14 @@ struct RenderPassData {
|
||||
return false;
|
||||
}
|
||||
|
||||
fml::ScopedCleanupClosure pop_cmd_debug_marker(
|
||||
[&gl]() { gl.PopDebugGroup(); });
|
||||
if (!command.label.empty()) {
|
||||
gl.PushDebugGroup(command.label);
|
||||
} else {
|
||||
pop_cmd_debug_marker.Release();
|
||||
}
|
||||
|
||||
const auto& pipeline = PipelineGLES::Cast(*command.pipeline);
|
||||
|
||||
const auto* color_attachment =
|
||||
@ -217,7 +282,7 @@ struct RenderPassData {
|
||||
viewport.rect.size.width, // width
|
||||
viewport.rect.size.height // height
|
||||
);
|
||||
if (pass_data.has_depth_attachment) {
|
||||
if (pass_data.depth_attachment) {
|
||||
gl.DepthRangef(viewport.depth_range.z_near, viewport.depth_range.z_far);
|
||||
}
|
||||
|
||||
@ -351,8 +416,25 @@ struct RenderPassData {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(csg): Respect the discard flags using glDiscardFramebuffer. Vital for
|
||||
// mobile GPUs.
|
||||
if (gl.DiscardFramebufferEXT.IsAvailable()) {
|
||||
std::vector<GLenum> attachments;
|
||||
if (pass_data.discard_color_attachment) {
|
||||
attachments.push_back(is_default_fbo ? GL_COLOR_EXT
|
||||
: GL_COLOR_ATTACHMENT0);
|
||||
}
|
||||
if (pass_data.discard_depth_attachment) {
|
||||
attachments.push_back(is_default_fbo ? GL_DEPTH_EXT
|
||||
: GL_DEPTH_ATTACHMENT);
|
||||
}
|
||||
if (pass_data.discard_stencil_attachment) {
|
||||
attachments.push_back(is_default_fbo ? GL_STENCIL_EXT
|
||||
: GL_STENCIL_ATTACHMENT);
|
||||
}
|
||||
gl.DiscardFramebufferEXT(GL_FRAMEBUFFER, // target
|
||||
attachments.size(), // attachments to discard
|
||||
attachments.data() // size
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -375,11 +457,13 @@ bool RenderPassGLES::EncodeCommands(
|
||||
const auto& stencil0 = render_target.GetStencilAttachment();
|
||||
|
||||
auto pass_data = std::make_shared<RenderPassData>();
|
||||
pass_data->label = label_;
|
||||
pass_data->viewport.rect = Rect::MakeSize(Size(GetRenderTargetSize()));
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// Setup color data.
|
||||
///
|
||||
pass_data->color_attachment = color0.texture;
|
||||
pass_data->clear_color = color0.clear_color;
|
||||
pass_data->clear_color_attachment = CanClearAttachment(color0.load_action);
|
||||
pass_data->discard_color_attachment =
|
||||
@ -389,7 +473,7 @@ bool RenderPassGLES::EncodeCommands(
|
||||
/// Setup depth data.
|
||||
///
|
||||
if (depth0.has_value()) {
|
||||
pass_data->has_depth_attachment = true;
|
||||
pass_data->depth_attachment = depth0->texture;
|
||||
pass_data->clear_depth = depth0->clear_depth;
|
||||
pass_data->clear_depth_attachment = CanClearAttachment(depth0->load_action);
|
||||
pass_data->discard_depth_attachment =
|
||||
@ -400,7 +484,7 @@ bool RenderPassGLES::EncodeCommands(
|
||||
/// Setup depth data.
|
||||
///
|
||||
if (stencil0.has_value()) {
|
||||
pass_data->has_stencil_attachment = true;
|
||||
pass_data->stencil_attachment = stencil0->texture;
|
||||
pass_data->clear_stencil = stencil0->clear_stencil;
|
||||
pass_data->clear_stencil_attachment =
|
||||
CanClearAttachment(stencil0->load_action);
|
||||
|
||||
@ -25,31 +25,33 @@ std::unique_ptr<Surface> SurfaceGLES::WrapFBO(std::shared_ptr<Context> context,
|
||||
const auto& gl_context = ContextGLES::Cast(*context);
|
||||
|
||||
TextureDescriptor color0_tex;
|
||||
color0_tex.type = TextureType::kTexture2D; // lies
|
||||
color0_tex.type = TextureType::kTexture2D;
|
||||
color0_tex.format = color_format;
|
||||
color0_tex.size = fbo_size;
|
||||
color0_tex.usage = static_cast<TextureUsageMask>(TextureUsage::kRenderTarget);
|
||||
color0_tex.sample_count = SampleCount::kCount4;
|
||||
color0_tex.sample_count = SampleCount::kCount1;
|
||||
|
||||
ColorAttachment color0;
|
||||
color0.texture = std::make_shared<TextureGLES>(gl_context.GetReactor(),
|
||||
std::move(color0_tex));
|
||||
color0.texture = std::make_shared<TextureGLES>(
|
||||
gl_context.GetReactor(), std::move(color0_tex),
|
||||
TextureGLES::IsWrapped::kWrapped);
|
||||
color0.clear_color = Color::DarkSlateGray();
|
||||
color0.load_action = LoadAction::kClear;
|
||||
color0.store_action = StoreAction::kStore;
|
||||
|
||||
TextureDescriptor stencil0_tex;
|
||||
stencil0_tex.type = TextureType::kTexture2D; // lies
|
||||
stencil0_tex.type = TextureType::kTexture2D;
|
||||
stencil0_tex.format = color_format;
|
||||
stencil0_tex.size = fbo_size;
|
||||
stencil0_tex.usage =
|
||||
static_cast<TextureUsageMask>(TextureUsage::kRenderTarget);
|
||||
stencil0_tex.sample_count = SampleCount::kCount4;
|
||||
stencil0_tex.sample_count = SampleCount::kCount1;
|
||||
|
||||
StencilAttachment stencil0;
|
||||
stencil0.clear_stencil = 0;
|
||||
stencil0.texture = std::make_shared<TextureGLES>(gl_context.GetReactor(),
|
||||
std::move(stencil0_tex));
|
||||
stencil0.texture = std::make_shared<TextureGLES>(
|
||||
gl_context.GetReactor(), std::move(stencil0_tex),
|
||||
TextureGLES::IsWrapped::kWrapped);
|
||||
stencil0.load_action = LoadAction::kClear;
|
||||
stencil0.store_action = StoreAction::kDontCare;
|
||||
|
||||
|
||||
@ -4,6 +4,8 @@
|
||||
|
||||
#include "impeller/renderer/backend/gles/texture_gles.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "flutter/fml/mapping.h"
|
||||
#include "impeller/base/allocation.h"
|
||||
#include "impeller/base/config.h"
|
||||
@ -11,15 +13,46 @@
|
||||
|
||||
namespace impeller {
|
||||
|
||||
static TextureGLES::Type GetTextureTypeFromDescriptor(
|
||||
const TextureDescriptor& desc) {
|
||||
const auto usage = static_cast<TextureUsageMask>(desc.usage);
|
||||
const auto render_target =
|
||||
static_cast<TextureUsageMask>(TextureUsage::kRenderTarget);
|
||||
if (usage == render_target) {
|
||||
return TextureGLES::Type::kRenderBuffer;
|
||||
}
|
||||
return TextureGLES::Type::kTexture;
|
||||
}
|
||||
|
||||
HandleType ToHandleType(TextureGLES::Type type) {
|
||||
switch (type) {
|
||||
case TextureGLES::Type::kTexture:
|
||||
return HandleType::kTexture;
|
||||
case TextureGLES::Type::kRenderBuffer:
|
||||
return HandleType::kRenderBuffer;
|
||||
}
|
||||
FML_UNREACHABLE();
|
||||
}
|
||||
|
||||
TextureGLES::TextureGLES(ReactorGLES::Ref reactor, TextureDescriptor desc)
|
||||
: TextureGLES(std::move(reactor), std::move(desc), false) {}
|
||||
|
||||
TextureGLES::TextureGLES(ReactorGLES::Ref reactor,
|
||||
TextureDescriptor desc,
|
||||
enum IsWrapped wrapped)
|
||||
: TextureGLES(std::move(reactor), std::move(desc), true) {}
|
||||
|
||||
TextureGLES::TextureGLES(std::shared_ptr<ReactorGLES> reactor,
|
||||
TextureDescriptor desc)
|
||||
TextureDescriptor desc,
|
||||
bool is_wrapped)
|
||||
: Texture(std::move(desc)),
|
||||
reactor_(reactor),
|
||||
handle_(reactor_->CreateHandle(HandleType::kTexture)) {
|
||||
type_(GetTextureTypeFromDescriptor(GetTextureDescriptor())),
|
||||
handle_(reactor_->CreateHandle(ToHandleType(type_))),
|
||||
is_wrapped_(is_wrapped) {
|
||||
if (!GetTextureDescriptor().IsValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
is_valid_ = true;
|
||||
}
|
||||
|
||||
@ -35,10 +68,10 @@ bool TextureGLES::IsValid() const {
|
||||
|
||||
// |Texture|
|
||||
void TextureGLES::SetLabel(const std::string_view& label) {
|
||||
if (!IsValid() || handle_.IsDead()) {
|
||||
return;
|
||||
label_ = std::string{label.data(), label.size()};
|
||||
if (contents_initialized_) {
|
||||
reactor_->SetDebugLabel(handle_, label_);
|
||||
}
|
||||
reactor_->SetDebugLabel(handle_, std::string{label.data(), label.size()});
|
||||
}
|
||||
|
||||
struct TexImage2DData {
|
||||
@ -47,6 +80,24 @@ struct TexImage2DData {
|
||||
GLenum type = GL_NONE;
|
||||
std::shared_ptr<fml::Mapping> data;
|
||||
|
||||
TexImage2DData(PixelFormat pixel_format) {
|
||||
switch (pixel_format) {
|
||||
case PixelFormat::kR8UNormInt:
|
||||
case PixelFormat::kR8G8B8A8UNormInt:
|
||||
case PixelFormat::kB8G8R8A8UNormInt:
|
||||
case PixelFormat::kR8G8B8A8UNormIntSRGB:
|
||||
case PixelFormat::kB8G8R8A8UNormIntSRGB:
|
||||
internal_format = GL_RGBA;
|
||||
format = GL_RGBA;
|
||||
type = GL_UNSIGNED_SHORT_4_4_4_4;
|
||||
break;
|
||||
case PixelFormat::kUnknown:
|
||||
case PixelFormat::kS8UInt:
|
||||
return;
|
||||
}
|
||||
is_valid_ = true;
|
||||
}
|
||||
|
||||
TexImage2DData(PixelFormat pixel_format,
|
||||
const uint8_t* contents,
|
||||
size_t length) {
|
||||
@ -108,6 +159,17 @@ bool TextureGLES::SetContents(const uint8_t* contents, size_t length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (GetType() != Type::kTexture) {
|
||||
VALIDATION_LOG << "Incorrect texture usage flags for setting contents on "
|
||||
"this texture object.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_wrapped_) {
|
||||
VALIDATION_LOG << "Cannot set the contents of a wrapped texture.";
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& tex_descriptor = GetTextureDescriptor();
|
||||
|
||||
if (tex_descriptor.size.IsEmpty()) {
|
||||
@ -142,20 +204,27 @@ bool TextureGLES::SetContents(const uint8_t* contents, size_t length) {
|
||||
}
|
||||
const auto& gl = reactor.GetProcTable();
|
||||
gl.BindTexture(GL_TEXTURE_2D, gl_handle.value());
|
||||
gl.TexImage2D(
|
||||
GL_TEXTURE_2D, // target
|
||||
0u, // LOD level (base mip level size checked)
|
||||
data->internal_format, // internal format
|
||||
size.width, // width
|
||||
size.height, // height
|
||||
0u, // border
|
||||
data->format, // format
|
||||
data->type, // type
|
||||
reinterpret_cast<const GLvoid*>(data->data->GetMapping()) // data
|
||||
const GLvoid* tex_data = nullptr;
|
||||
if (data->data) {
|
||||
tex_data = data->data->GetMapping();
|
||||
}
|
||||
gl.TexImage2D(GL_TEXTURE_2D, // target
|
||||
0u, // LOD level
|
||||
data->internal_format, // internal format
|
||||
size.width, // width
|
||||
size.height, // height
|
||||
0u, // border
|
||||
data->format, // format
|
||||
data->type, // type
|
||||
tex_data // data
|
||||
);
|
||||
};
|
||||
|
||||
return reactor_->AddOperation(texture_upload);
|
||||
contents_initialized_ = reactor_->AddOperation(texture_upload);
|
||||
if (contents_initialized_) {
|
||||
reactor_->SetDebugLabel(handle_, label_);
|
||||
}
|
||||
return contents_initialized_;
|
||||
}
|
||||
|
||||
// |Texture|
|
||||
@ -163,6 +232,85 @@ ISize TextureGLES::GetSize() const {
|
||||
return GetTextureDescriptor().size;
|
||||
}
|
||||
|
||||
static std::optional<GLenum> ToRenderBufferFormat(PixelFormat format) {
|
||||
switch (format) {
|
||||
case PixelFormat::kB8G8R8A8UNormInt:
|
||||
case PixelFormat::kR8G8B8A8UNormInt:
|
||||
return GL_RGBA4;
|
||||
case PixelFormat::kS8UInt:
|
||||
return GL_STENCIL_INDEX8;
|
||||
case PixelFormat::kUnknown:
|
||||
case PixelFormat::kR8UNormInt:
|
||||
case PixelFormat::kR8G8B8A8UNormIntSRGB:
|
||||
case PixelFormat::kB8G8R8A8UNormIntSRGB:
|
||||
return std::nullopt;
|
||||
}
|
||||
FML_UNREACHABLE();
|
||||
}
|
||||
|
||||
void TextureGLES::InitializeContentsIfNecessary() const {
|
||||
if (!IsValid()) {
|
||||
return;
|
||||
}
|
||||
if (contents_initialized_) {
|
||||
return;
|
||||
}
|
||||
contents_initialized_ = true;
|
||||
|
||||
if (is_wrapped_) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto size = GetSize();
|
||||
|
||||
if (size.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& gl = reactor_->GetProcTable();
|
||||
auto handle = reactor_->GetGLHandle(handle_);
|
||||
if (!handle.has_value()) {
|
||||
VALIDATION_LOG << "Could not initialize the contents of texture.";
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type_) {
|
||||
case Type::kTexture: {
|
||||
TexImage2DData tex_data(GetTextureDescriptor().format);
|
||||
if (!tex_data.IsValid()) {
|
||||
VALIDATION_LOG << "Invalid format for texture image.";
|
||||
return;
|
||||
}
|
||||
gl.BindTexture(GL_TEXTURE_2D, handle.value());
|
||||
gl.TexImage2D(GL_TEXTURE_2D, // target
|
||||
0u, // LOD level (base mip level size checked)
|
||||
tex_data.internal_format, // internal format
|
||||
size.width, // width
|
||||
size.height, // height
|
||||
0u, // border
|
||||
tex_data.format, // format
|
||||
tex_data.type, // type
|
||||
nullptr // data
|
||||
);
|
||||
} break;
|
||||
case Type::kRenderBuffer:
|
||||
auto render_buffer_format =
|
||||
ToRenderBufferFormat(GetTextureDescriptor().format);
|
||||
if (!render_buffer_format.has_value()) {
|
||||
VALIDATION_LOG << "Invalid format for render-buffer image.";
|
||||
return;
|
||||
}
|
||||
gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value());
|
||||
gl.RenderbufferStorage(GL_RENDERBUFFER, // target
|
||||
render_buffer_format.value(), // internal format
|
||||
size.width, // width
|
||||
size.height // height
|
||||
);
|
||||
break;
|
||||
}
|
||||
reactor_->SetDebugLabel(handle_, label_);
|
||||
}
|
||||
|
||||
bool TextureGLES::Bind() const {
|
||||
if (!IsValid()) {
|
||||
return false;
|
||||
@ -172,7 +320,61 @@ bool TextureGLES::Bind() const {
|
||||
return false;
|
||||
}
|
||||
const auto& gl = reactor_->GetProcTable();
|
||||
gl.BindTexture(GL_TEXTURE_2D, handle.value());
|
||||
switch (type_) {
|
||||
case Type::kTexture:
|
||||
gl.BindTexture(GL_TEXTURE_2D, handle.value());
|
||||
break;
|
||||
case Type::kRenderBuffer:
|
||||
gl.BindRenderbuffer(GL_RENDERBUFFER, handle.value());
|
||||
break;
|
||||
}
|
||||
InitializeContentsIfNecessary();
|
||||
return true;
|
||||
}
|
||||
|
||||
TextureGLES::Type TextureGLES::GetType() const {
|
||||
return type_;
|
||||
}
|
||||
|
||||
static GLenum ToAttachmentPoint(TextureGLES::AttachmentPoint point) {
|
||||
switch (point) {
|
||||
case TextureGLES::AttachmentPoint::kColor0:
|
||||
return GL_COLOR_ATTACHMENT0;
|
||||
case TextureGLES::AttachmentPoint::kDepth:
|
||||
return GL_DEPTH_ATTACHMENT;
|
||||
case TextureGLES::AttachmentPoint::kStencil:
|
||||
return GL_STENCIL_ATTACHMENT;
|
||||
}
|
||||
}
|
||||
|
||||
bool TextureGLES::SetAsFramebufferAttachment(GLuint fbo,
|
||||
AttachmentPoint point) const {
|
||||
if (!IsValid()) {
|
||||
return false;
|
||||
}
|
||||
InitializeContentsIfNecessary();
|
||||
auto handle = reactor_->GetGLHandle(handle_);
|
||||
if (!handle.has_value()) {
|
||||
return false;
|
||||
}
|
||||
const auto& gl = reactor_->GetProcTable();
|
||||
switch (type_) {
|
||||
case Type::kTexture:
|
||||
gl.FramebufferTexture2D(GL_FRAMEBUFFER, // target
|
||||
ToAttachmentPoint(point), // attachment
|
||||
GL_TEXTURE_2D, // textarget
|
||||
handle.value(), // texture
|
||||
0 // level
|
||||
);
|
||||
break;
|
||||
case Type::kRenderBuffer:
|
||||
gl.FramebufferRenderbuffer(GL_FRAMEBUFFER, // target
|
||||
ToAttachmentPoint(point), // attachment
|
||||
GL_RENDERBUFFER, // render-buffer target
|
||||
handle.value() // render-buffer
|
||||
);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -15,20 +15,53 @@ namespace impeller {
|
||||
class TextureGLES final : public Texture,
|
||||
public BackendCast<TextureGLES, Texture> {
|
||||
public:
|
||||
enum class Type {
|
||||
kTexture,
|
||||
kRenderBuffer,
|
||||
};
|
||||
|
||||
enum class IsWrapped {
|
||||
kWrapped,
|
||||
};
|
||||
|
||||
TextureGLES(ReactorGLES::Ref reactor, TextureDescriptor desc);
|
||||
|
||||
TextureGLES(ReactorGLES::Ref reactor,
|
||||
TextureDescriptor desc,
|
||||
IsWrapped wrapped);
|
||||
|
||||
// |Texture|
|
||||
~TextureGLES() override;
|
||||
|
||||
bool Bind() const;
|
||||
[[nodiscard]] bool Bind() const;
|
||||
|
||||
enum class AttachmentPoint {
|
||||
kColor0,
|
||||
kDepth,
|
||||
kStencil,
|
||||
};
|
||||
[[nodiscard]] bool SetAsFramebufferAttachment(GLuint fbo,
|
||||
AttachmentPoint point) const;
|
||||
|
||||
Type GetType() const;
|
||||
|
||||
bool IsWrapped() const { return is_wrapped_; }
|
||||
|
||||
private:
|
||||
friend class AllocatorMTL;
|
||||
|
||||
ReactorGLES::Ref reactor_;
|
||||
const Type type_;
|
||||
GLESHandle handle_;
|
||||
mutable bool contents_initialized_ = false;
|
||||
const bool is_wrapped_;
|
||||
std::string label_;
|
||||
bool is_valid_ = false;
|
||||
|
||||
TextureGLES(std::shared_ptr<ReactorGLES> reactor,
|
||||
TextureDescriptor desc,
|
||||
bool is_wrapped);
|
||||
|
||||
// |Texture|
|
||||
void SetLabel(const std::string_view& label) override;
|
||||
|
||||
@ -41,6 +74,8 @@ class TextureGLES final : public Texture,
|
||||
// |Texture|
|
||||
ISize GetSize() const override;
|
||||
|
||||
void InitializeContentsIfNecessary() const;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(TextureGLES);
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user