[impeller] Add missing pieces to the OpenGLES backend. (flutter/engine#33223)

This commit is contained in:
Chinmay Garde 2022-05-09 23:59:04 -07:00 committed by GitHub
parent caf8268037
commit eb4a892f0c
12 changed files with 456 additions and 42 deletions

View File

@ -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());

View File

@ -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) {

View File

@ -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) {

View File

@ -21,7 +21,7 @@ DeviceBufferGLES::DeviceBufferGLES(ReactorGLES::Ref reactor,
// |DeviceBuffer|
DeviceBufferGLES::~DeviceBufferGLES() {
if (!reactor_) {
if (!handle_.IsDead()) {
reactor_->CollectHandle(handle_);
}
}

View File

@ -21,6 +21,8 @@ enum class HandleType {
kTexture,
kBuffer,
kProgram,
kRenderBuffer,
kFrameBuffer,
};
class ReactorGLES;

View File

@ -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

View File

@ -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);
};

View File

@ -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);
}

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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);
};