未验证 提交 26fe9125 编写于 作者: K Kaushik Iska 提交者: GitHub

[embedder] Add FBO callback that takes frame info (#20617)

上级 b59793ee
......@@ -60,7 +60,7 @@ bool ShellTestPlatformViewGL::GLContextPresent() {
}
// |GPUSurfaceGLDelegate|
intptr_t ShellTestPlatformViewGL::GLContextFBO() const {
intptr_t ShellTestPlatformViewGL::GLContextFBO(GLFrameInfo frame_info) const {
return gl_surface_.GetFramebuffer();
}
......
......@@ -56,7 +56,7 @@ class ShellTestPlatformViewGL : public ShellTestPlatformView,
bool GLContextPresent() override;
// |GPUSurfaceGLDelegate|
intptr_t GLContextFBO() const override;
intptr_t GLContextFBO(GLFrameInfo frame_info) const override;
// |GPUSurfaceGLDelegate|
GLProcResolver GetGLProcResolver() const override;
......
......@@ -204,10 +204,12 @@ bool GPUSurfaceGL::CreateOrUpdateSurfaces(const SkISize& size) {
sk_sp<SkSurface> onscreen_surface;
GLFrameInfo frame_info = {static_cast<uint32_t>(size.width()),
static_cast<uint32_t>(size.height())};
onscreen_surface =
WrapOnscreenSurface(context_.get(), // GL context
size, // root surface size
delegate_->GLContextFBO() // window FBO ID
WrapOnscreenSurface(context_.get(), // GL context
size, // root surface size
delegate_->GLContextFBO(frame_info) // window FBO ID
);
if (onscreen_surface == nullptr) {
......@@ -287,13 +289,16 @@ bool GPUSurfaceGL::PresentSurface(SkCanvas* canvas) {
auto current_size =
SkISize::Make(onscreen_surface_->width(), onscreen_surface_->height());
GLFrameInfo frame_info = {static_cast<uint32_t>(current_size.width()),
static_cast<uint32_t>(current_size.height())};
// The FBO has changed, ask the delegate for the new FBO and do a surface
// re-wrap.
auto new_onscreen_surface =
WrapOnscreenSurface(context_.get(), // GL context
current_size, // root surface size
delegate_->GLContextFBO() // window FBO ID
);
auto new_onscreen_surface = WrapOnscreenSurface(
context_.get(), // GL context
current_size, // root surface size
delegate_->GLContextFBO(frame_info) // window FBO ID
);
if (!new_onscreen_surface) {
return false;
......
......@@ -14,6 +14,13 @@
namespace flutter {
// A structure to represent the frame information which is passed to the
// embedder when requesting a frame buffer object.
struct GLFrameInfo {
uint32_t width;
uint32_t height;
};
class GPUSurfaceGLDelegate : public GPUSurfaceDelegate {
public:
~GPUSurfaceGLDelegate() override;
......@@ -33,13 +40,13 @@ class GPUSurfaceGLDelegate : public GPUSurfaceDelegate {
virtual bool GLContextPresent() = 0;
// The ID of the main window bound framebuffer. Typically FBO0.
virtual intptr_t GLContextFBO() const = 0;
virtual intptr_t GLContextFBO(GLFrameInfo frame_info) const = 0;
// The rendering subsystem assumes that the ID of the main window bound
// framebuffer remains constant throughout. If this assumption in incorrect,
// embedders are required to return true from this method. In such cases,
// GLContextFBO() will be called again to acquire the new FBO ID for rendering
// subsequent frames.
// GLContextFBO(frame_info) will be called again to acquire the new FBO ID for
// rendering subsequent frames.
virtual bool GLContextFBOResetAfterPresent() const;
// Indicates whether or not the surface supports pixel readback as used in
......
......@@ -115,7 +115,7 @@ bool AndroidSurfaceGL::GLContextPresent() {
return onscreen_surface_->SwapBuffers();
}
intptr_t AndroidSurfaceGL::GLContextFBO() const {
intptr_t AndroidSurfaceGL::GLContextFBO(GLFrameInfo frame_info) const {
FML_DCHECK(IsValid());
// The default window bound framebuffer on Android.
return 0;
......
......@@ -59,7 +59,7 @@ class AndroidSurfaceGL final : public GPUSurfaceGLDelegate,
bool GLContextPresent() override;
// |GPUSurfaceGLDelegate|
intptr_t GLContextFBO() const override;
intptr_t GLContextFBO(GLFrameInfo frame_info) const override;
// |GPUSurfaceGLDelegate|
ExternalViewEmbedder* GetExternalViewEmbedder() override;
......
......@@ -18,7 +18,7 @@ bool AndroidSurfaceMock::GLContextPresent() {
return true;
}
intptr_t AndroidSurfaceMock::GLContextFBO() const {
intptr_t AndroidSurfaceMock::GLContextFBO(GLFrameInfo frame_info) const {
return 0;
}
......
......@@ -48,7 +48,7 @@ class AndroidSurfaceMock final : public GPUSurfaceGLDelegate,
bool GLContextPresent() override;
// |GPUSurfaceGLDelegate|
intptr_t GLContextFBO() const override;
intptr_t GLContextFBO(GLFrameInfo frame_info) const override;
// |GPUSurfaceGLDelegate|
ExternalViewEmbedder* GetExternalViewEmbedder() override;
......
......@@ -43,7 +43,7 @@ class IOSSurfaceGL final : public IOSSurface, public GPUSurfaceGLDelegate {
bool GLContextPresent() override;
// |GPUSurfaceGLDelegate|
intptr_t GLContextFBO() const override;
intptr_t GLContextFBO(GLFrameInfo frame_info) const override;
// |GPUSurfaceGLDelegate|
bool SurfaceSupportsReadback() const override;
......
......@@ -44,7 +44,7 @@ std::unique_ptr<Surface> IOSSurfaceGL::CreateGPUSurface(GrDirectContext* gr_cont
}
// |GPUSurfaceGLDelegate|
intptr_t IOSSurfaceGL::GLContextFBO() const {
intptr_t IOSSurfaceGL::GLContextFBO(GLFrameInfo frame_info) const {
return IsValid() ? render_target_->GetFramebuffer() : GL_NONE;
}
......
......@@ -93,8 +93,17 @@ static bool IsOpenGLRendererConfigValid(const FlutterRendererConfig* config) {
if (SAFE_ACCESS(open_gl_config, make_current, nullptr) == nullptr ||
SAFE_ACCESS(open_gl_config, clear_current, nullptr) == nullptr ||
SAFE_ACCESS(open_gl_config, present, nullptr) == nullptr ||
SAFE_ACCESS(open_gl_config, fbo_callback, nullptr) == nullptr) {
SAFE_ACCESS(open_gl_config, present, nullptr) == nullptr) {
return false;
}
bool fbo_callback_exists =
SAFE_ACCESS(open_gl_config, fbo_callback, nullptr) != nullptr;
bool fbo_with_frame_info_callback_exists =
SAFE_ACCESS(open_gl_config, fbo_with_frame_info_callback, nullptr) !=
nullptr;
// only one of these callbacks must exist.
if (fbo_callback_exists == fbo_with_frame_info_callback_exists) {
return false;
}
......@@ -168,8 +177,20 @@ InferOpenGLPlatformViewCreationCallback(
return ptr(user_data);
};
auto gl_fbo_callback = [ptr = config->open_gl.fbo_callback,
user_data]() -> intptr_t { return ptr(user_data); };
auto gl_fbo_callback =
[fbo_callback = config->open_gl.fbo_callback,
fbo_with_frame_info_callback =
config->open_gl.fbo_with_frame_info_callback,
user_data](flutter::GLFrameInfo gl_frame_info) -> intptr_t {
if (fbo_callback) {
return fbo_callback(user_data);
} else {
FlutterFrameInfo frame_info = {};
frame_info.struct_size = sizeof(FlutterFrameInfo);
frame_info.size = {gl_frame_info.width, gl_frame_info.height};
return fbo_with_frame_info_callback(user_data, &frame_info);
}
};
const FlutterOpenGLRendererConfig* open_gl_config = &config->open_gl;
std::function<bool()> gl_make_resource_current_callback = nullptr;
......
......@@ -306,12 +306,46 @@ typedef bool (*TextureFrameCallback)(void* /* user data */,
FlutterOpenGLTexture* /* texture out */);
typedef void (*VsyncCallback)(void* /* user data */, intptr_t /* baton */);
/// A structure to represent the width and height.
typedef struct {
double width;
double height;
} FlutterSize;
/// A structure to represent the width and height.
///
/// See: \ref FlutterSize when the value are not integers.
typedef struct {
uint32_t width;
uint32_t height;
} FlutterUIntSize;
/// This information is passed to the embedder when requesting a frame buffer
/// object.
///
/// See: \ref FlutterSoftwareRendererConfig.fbo_with_frame_info_callback.
typedef struct {
/// The size of this struct. Must be sizeof(FlutterFrameInfo).
size_t struct_size;
/// The size of the surface that will be backed by the fbo.
FlutterUIntSize size;
} FlutterFrameInfo;
typedef uint32_t (*UIntFrameInfoCallback)(
void* /* user data */,
const FlutterFrameInfo* /* frame info */);
typedef struct {
/// The size of this struct. Must be sizeof(FlutterOpenGLRendererConfig).
size_t struct_size;
BoolCallback make_current;
BoolCallback clear_current;
BoolCallback present;
/// Specifying one (and only one) of the `fbo_callback` or
/// `fbo_with_frame_info_callback` is required. Specifying both is an error
/// and engine intialization will be terminated. The return value indicates
/// the id of the frame buffer object that flutter will obtain the gl surface
/// from.
UIntCallback fbo_callback;
/// This is an optional callback. Flutter will ask the emebdder to create a GL
/// context current on a background thread. If the embedder is able to do so,
......@@ -342,6 +376,14 @@ typedef struct {
/// that external texture details can be supplied to the engine for subsequent
/// composition.
TextureFrameCallback gl_external_texture_frame_callback;
/// Specifying one (and only one) of the `fbo_callback` or
/// `fbo_with_frame_info_callback` is required. Specifying both is an error
/// and engine intialization will be terminated. The return value indicates
/// the id of the frame buffer object (fbo) that flutter will obtain the gl
/// surface from. When using this variant, the embedder is passed a
/// `FlutterFrameInfo` struct that indicates the properties of the surface
/// that flutter will acquire from the returned fbo.
UIntFrameInfoCallback fbo_with_frame_info_callback;
} FlutterOpenGLRendererConfig;
typedef struct {
......@@ -502,11 +544,6 @@ typedef struct {
double y;
} FlutterPoint;
typedef struct {
double width;
double height;
} FlutterSize;
typedef struct {
FlutterRect rect;
FlutterSize upper_left_corner_radius;
......
......@@ -50,8 +50,8 @@ bool EmbedderSurfaceGL::GLContextPresent() {
}
// |GPUSurfaceGLDelegate|
intptr_t EmbedderSurfaceGL::GLContextFBO() const {
return gl_dispatch_table_.gl_fbo_callback();
intptr_t EmbedderSurfaceGL::GLContextFBO(GLFrameInfo frame_info) const {
return gl_dispatch_table_.gl_fbo_callback(frame_info);
}
// |GPUSurfaceGLDelegate|
......
......@@ -19,7 +19,7 @@ class EmbedderSurfaceGL final : public EmbedderSurface,
std::function<bool(void)> gl_make_current_callback; // required
std::function<bool(void)> gl_clear_current_callback; // required
std::function<bool(void)> gl_present_callback; // required
std::function<intptr_t(void)> gl_fbo_callback; // required
std::function<intptr_t(GLFrameInfo)> gl_fbo_callback; // required
std::function<bool(void)> gl_make_resource_current_callback; // optional
std::function<SkMatrix(void)>
gl_surface_transformation_callback; // optional
......@@ -59,7 +59,7 @@ class EmbedderSurfaceGL final : public EmbedderSurface,
bool GLContextPresent() override;
// |GPUSurfaceGLDelegate|
intptr_t GLContextFBO() const override;
intptr_t GLContextFBO(GLFrameInfo frame_info) const override;
// |GPUSurfaceGLDelegate|
bool GLContextFBOResetAfterPresent() const override;
......
......@@ -35,8 +35,10 @@ EmbedderConfigBuilder::EmbedderConfigBuilder(
opengl_renderer_config_.present = [](void* context) -> bool {
return reinterpret_cast<EmbedderTestContext*>(context)->GLPresent();
};
opengl_renderer_config_.fbo_callback = [](void* context) -> uint32_t {
return reinterpret_cast<EmbedderTestContext*>(context)->GLGetFramebuffer();
opengl_renderer_config_.fbo_with_frame_info_callback =
[](void* context, const FlutterFrameInfo* frame_info) -> uint32_t {
return reinterpret_cast<EmbedderTestContext*>(context)->GLGetFramebuffer(
*frame_info);
};
opengl_renderer_config_.make_resource_current = [](void* context) -> bool {
return reinterpret_cast<EmbedderTestContext*>(context)
......@@ -110,6 +112,21 @@ void EmbedderConfigBuilder::SetSoftwareRendererConfig(SkISize surface_size) {
context_.SetupOpenGLSurface(surface_size);
}
void EmbedderConfigBuilder::SetOpenGLFBOCallBack() {
// SetOpenGLRendererConfig must be called before this.
FML_CHECK(renderer_config_.type == FlutterRendererType::kOpenGL);
renderer_config_.open_gl.fbo_callback = [](void* context) -> uint32_t {
FlutterFrameInfo frame_info = {};
// fbo_callback doesn't use the frame size information, only
// fbo_callback_with_frame_info does.
frame_info.struct_size = sizeof(FlutterFrameInfo);
frame_info.size.width = 0;
frame_info.size.height = 0;
return reinterpret_cast<EmbedderTestContext*>(context)->GLGetFramebuffer(
frame_info);
};
}
void EmbedderConfigBuilder::SetOpenGLRendererConfig(SkISize surface_size) {
renderer_config_.type = FlutterRendererType::kOpenGL;
renderer_config_.open_gl = opengl_renderer_config_;
......
......@@ -49,6 +49,12 @@ class EmbedderConfigBuilder {
void SetOpenGLRendererConfig(SkISize surface_size);
// Used to explicitly set an `open_gl.fbo_callback`. Using this method will
// cause your test to fail since the ctor for this class sets
// `open_gl.fbo_callback_with_frame_info`. This method exists as a utility to
// explicitly test this behavior.
void SetOpenGLFBOCallBack();
void SetAssetsPath();
void SetSnapshots();
......
......@@ -197,11 +197,16 @@ bool EmbedderTestContext::GLPresent() {
return true;
}
uint32_t EmbedderTestContext::GLGetFramebuffer() {
uint32_t EmbedderTestContext::GLGetFramebuffer(FlutterFrameInfo frame_info) {
FML_CHECK(gl_surface_) << "GL surface must be initialized.";
gl_surface_fbo_frame_infos_.push_back(frame_info);
return gl_surface_->GetFramebuffer();
}
std::vector<FlutterFrameInfo> EmbedderTestContext::GetGLFBOFrameInfos() {
return gl_surface_fbo_frame_infos_;
}
bool EmbedderTestContext::GLMakeResourceCurrent() {
FML_CHECK(gl_surface_) << "GL surface must be initialized.";
return gl_surface_->MakeResourceCurrent();
......
......@@ -79,6 +79,9 @@ class EmbedderTestContext {
size_t GetSoftwareSurfacePresentCount() const;
// Returns the frame information for all the frames that were rendered.
std::vector<FlutterFrameInfo> GetGLFBOFrameInfos();
private:
// This allows the builder to access the hooks.
friend class EmbedderConfigBuilder;
......@@ -101,6 +104,7 @@ class EmbedderTestContext {
std::unique_ptr<EmbedderTestCompositor> compositor_;
NextSceneCallback next_scene_callback_;
SkMatrix root_surface_transformation_;
std::vector<FlutterFrameInfo> gl_surface_fbo_frame_infos_;
size_t gl_surface_present_count_ = 0;
size_t software_surface_present_count_ = 0;
......@@ -133,7 +137,7 @@ class EmbedderTestContext {
bool GLPresent();
uint32_t GLGetFramebuffer();
uint32_t GLGetFramebuffer(FlutterFrameInfo frame_info);
bool GLMakeResourceCurrent();
......
......@@ -4352,5 +4352,60 @@ TEST_F(EmbedderTest, CanLaunchAndShutdownWithAValidElfSource) {
engine.reset();
}
TEST_F(EmbedderTest, FrameInfoContainsValidWidthAndHeight) {
auto& context = GetEmbedderContext();
EmbedderConfigBuilder builder(context);
builder.SetOpenGLRendererConfig(SkISize::Make(600, 1024));
builder.SetDartEntrypoint("push_frames_over_and_over");
const auto root_surface_transformation =
SkMatrix().preTranslate(0, 1024).preRotate(-90, 0, 0);
context.SetRootSurfaceTransformation(root_surface_transformation);
auto engine = builder.LaunchEngine();
// Send a window metrics events so frames may be scheduled.
FlutterWindowMetricsEvent event = {};
event.struct_size = sizeof(event);
event.width = 1024;
event.height = 600;
event.pixel_ratio = 1.0;
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
kSuccess);
ASSERT_TRUE(engine.is_valid());
constexpr size_t frames_expected = 10;
fml::CountDownLatch frame_latch(frames_expected);
size_t frames_seen = 0;
context.AddNativeCallback("SignalNativeTest",
CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
frames_seen++;
frame_latch.CountDown();
}));
frame_latch.Wait();
ASSERT_EQ(frames_expected, frames_seen);
ASSERT_EQ(context.GetGLFBOFrameInfos().size(), frames_seen);
for (FlutterFrameInfo frame_info : context.GetGLFBOFrameInfos()) {
// width and height are rotated by 90 deg
ASSERT_EQ(frame_info.size.width, event.height);
ASSERT_EQ(frame_info.size.height, event.width);
}
}
TEST_F(EmbedderTest, MustNotRunWithBothFBOCallbacksSet) {
auto& context = GetEmbedderContext();
EmbedderConfigBuilder builder(context);
builder.SetOpenGLRendererConfig(SkISize::Make(600, 1024));
builder.SetOpenGLFBOCallBack();
auto engine = builder.LaunchEngine();
ASSERT_FALSE(engine.is_valid());
}
} // namespace testing
} // namespace flutter
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册