mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Converting a large variety of classes involved in tracking surfaces, frames, surface damage, etc. to using the DisplayList/Impeller geometry classes. Addresses a bullet item in https://github.com/flutter/flutter/issues/161456 --------- Co-authored-by: Reid Baker <1063596+reidbaker@users.noreply.github.com>
265 lines
8.1 KiB
C++
265 lines
8.1 KiB
C++
// 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 "flutter/testing/test_gl_surface.h"
|
|
|
|
#include <EGL/egl.h>
|
|
#include <GLES2/gl2.h>
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
#include "flutter/fml/logging.h"
|
|
#include "flutter/testing/test_gl_utils.h"
|
|
#include "third_party/skia/include/core/SkColorSpace.h"
|
|
#include "third_party/skia/include/core/SkColorType.h"
|
|
#include "third_party/skia/include/core/SkSurface.h"
|
|
#include "third_party/skia/include/gpu/ganesh/GrBackendSurface.h"
|
|
#include "third_party/skia/include/gpu/ganesh/SkSurfaceGanesh.h"
|
|
#include "third_party/skia/include/gpu/ganesh/gl/GrGLAssembleInterface.h"
|
|
#include "third_party/skia/include/gpu/ganesh/gl/GrGLBackendSurface.h"
|
|
#include "third_party/skia/include/gpu/ganesh/gl/GrGLDirectContext.h"
|
|
#include "third_party/skia/include/gpu/ganesh/gl/GrGLTypes.h"
|
|
|
|
namespace flutter::testing {
|
|
|
|
TestGLOnscreenOnlySurface::TestGLOnscreenOnlySurface(
|
|
std::shared_ptr<TestEGLContext> context,
|
|
DlISize size)
|
|
: surface_size_(size), egl_context_(std::move(context)) {
|
|
const EGLint attributes[] = {
|
|
EGL_WIDTH, size.width, //
|
|
EGL_HEIGHT, size.height, //
|
|
EGL_NONE,
|
|
};
|
|
|
|
onscreen_surface_ =
|
|
::eglCreatePbufferSurface(egl_context_->display, // display connection
|
|
egl_context_->config, // config
|
|
attributes // surface attributes
|
|
);
|
|
FML_CHECK(onscreen_surface_ != EGL_NO_SURFACE) << GetEGLError();
|
|
}
|
|
|
|
TestGLOnscreenOnlySurface::~TestGLOnscreenOnlySurface() {
|
|
skia_context_ = nullptr;
|
|
|
|
auto result = ::eglDestroySurface(egl_context_->display, onscreen_surface_);
|
|
FML_CHECK(result == EGL_TRUE) << GetEGLError();
|
|
}
|
|
|
|
const DlISize& TestGLOnscreenOnlySurface::GetSurfaceSize() const {
|
|
return surface_size_;
|
|
}
|
|
|
|
bool TestGLOnscreenOnlySurface::MakeCurrent() {
|
|
auto result =
|
|
::eglMakeCurrent(egl_context_->display, onscreen_surface_,
|
|
onscreen_surface_, egl_context_->onscreen_context);
|
|
|
|
if (result == EGL_FALSE) {
|
|
FML_LOG(ERROR) << "Could not make the context current. " << GetEGLError();
|
|
}
|
|
|
|
return result == EGL_TRUE;
|
|
}
|
|
|
|
bool TestGLOnscreenOnlySurface::ClearCurrent() {
|
|
auto result = ::eglMakeCurrent(egl_context_->display, EGL_NO_SURFACE,
|
|
EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
|
|
|
if (result == EGL_FALSE) {
|
|
FML_LOG(ERROR) << "Could not clear the current context. " << GetEGLError();
|
|
}
|
|
|
|
return result == EGL_TRUE;
|
|
}
|
|
|
|
bool TestGLOnscreenOnlySurface::Present() {
|
|
auto result = ::eglSwapBuffers(egl_context_->display, onscreen_surface_);
|
|
|
|
if (result == EGL_FALSE) {
|
|
FML_LOG(ERROR) << "Could not swap buffers. " << GetEGLError();
|
|
}
|
|
|
|
return result == EGL_TRUE;
|
|
}
|
|
|
|
uint32_t TestGLOnscreenOnlySurface::GetFramebuffer(uint32_t width,
|
|
uint32_t height) const {
|
|
return GetWindowFBOId();
|
|
}
|
|
|
|
void* TestGLOnscreenOnlySurface::GetProcAddress(const char* name) const {
|
|
if (name == nullptr) {
|
|
return nullptr;
|
|
}
|
|
auto symbol = ::eglGetProcAddress(name);
|
|
if (symbol == NULL) {
|
|
FML_LOG(ERROR) << "Could not fetch symbol for name: " << name;
|
|
}
|
|
return reinterpret_cast<void*>(symbol);
|
|
}
|
|
|
|
sk_sp<GrDirectContext> TestGLOnscreenOnlySurface::GetGrContext() {
|
|
if (skia_context_) {
|
|
return skia_context_;
|
|
}
|
|
|
|
return CreateGrContext();
|
|
}
|
|
|
|
sk_sp<GrDirectContext> TestGLOnscreenOnlySurface::CreateGrContext() {
|
|
if (!MakeCurrent()) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto get_string =
|
|
reinterpret_cast<PFNGLGETSTRINGPROC>(GetProcAddress("glGetString"));
|
|
|
|
if (!get_string) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto c_version = reinterpret_cast<const char*>(get_string(GL_VERSION));
|
|
|
|
if (c_version == NULL) {
|
|
return nullptr;
|
|
}
|
|
|
|
GrGLGetProc get_proc = [](void* context, const char name[]) -> GrGLFuncPtr {
|
|
return reinterpret_cast<GrGLFuncPtr>(
|
|
reinterpret_cast<TestGLOnscreenOnlySurface*>(context)->GetProcAddress(
|
|
name));
|
|
};
|
|
|
|
std::string version(c_version);
|
|
auto interface = version.find("OpenGL ES") == std::string::npos
|
|
? GrGLMakeAssembledGLInterface(this, get_proc)
|
|
: GrGLMakeAssembledGLESInterface(this, get_proc);
|
|
|
|
if (!interface) {
|
|
return nullptr;
|
|
}
|
|
|
|
skia_context_ = GrDirectContexts::MakeGL(interface);
|
|
return skia_context_;
|
|
}
|
|
|
|
sk_sp<SkSurface> TestGLOnscreenOnlySurface::GetOnscreenSurface() {
|
|
FML_CHECK(::eglGetCurrentContext() != EGL_NO_CONTEXT);
|
|
|
|
GrGLFramebufferInfo framebuffer_info = {};
|
|
const uint32_t width = surface_size_.width;
|
|
const uint32_t height = surface_size_.height;
|
|
framebuffer_info.fFBOID = GetFramebuffer(width, height);
|
|
#if FML_OS_MACOSX
|
|
framebuffer_info.fFormat = 0x8058; // GL_RGBA8
|
|
#else
|
|
framebuffer_info.fFormat = 0x93A1; // GL_BGRA8;
|
|
#endif
|
|
|
|
auto backend_render_target =
|
|
GrBackendRenderTargets::MakeGL(width, // width
|
|
height, // height
|
|
1, // sample count
|
|
8, // stencil bits
|
|
framebuffer_info // framebuffer info
|
|
);
|
|
|
|
SkSurfaceProps surface_properties(0, kUnknown_SkPixelGeometry);
|
|
|
|
auto surface = SkSurfaces::WrapBackendRenderTarget(
|
|
GetGrContext().get(), // context
|
|
backend_render_target, // backend render target
|
|
kBottomLeft_GrSurfaceOrigin, // surface origin
|
|
kN32_SkColorType, // color type
|
|
SkColorSpace::MakeSRGB(), // color space
|
|
&surface_properties, // surface properties
|
|
nullptr, // release proc
|
|
nullptr // release context
|
|
);
|
|
|
|
if (!surface) {
|
|
FML_LOG(ERROR) << "Could not wrap the surface while attempting to "
|
|
"snapshot the GL surface.";
|
|
return nullptr;
|
|
}
|
|
|
|
return surface;
|
|
}
|
|
|
|
sk_sp<SkImage> TestGLOnscreenOnlySurface::GetRasterSurfaceSnapshot() {
|
|
auto surface = GetOnscreenSurface();
|
|
|
|
if (!surface) {
|
|
FML_LOG(ERROR) << "Aborting snapshot because of on-screen surface "
|
|
"acquisition failure.";
|
|
return nullptr;
|
|
}
|
|
|
|
auto device_snapshot = surface->makeImageSnapshot();
|
|
|
|
if (!device_snapshot) {
|
|
FML_LOG(ERROR) << "Could not create the device snapshot while attempting "
|
|
"to snapshot the GL surface.";
|
|
return nullptr;
|
|
}
|
|
|
|
auto host_snapshot = device_snapshot->makeRasterImage(nullptr);
|
|
|
|
if (!host_snapshot) {
|
|
FML_LOG(ERROR) << "Could not create the host snapshot while attempting to "
|
|
"snapshot the GL surface.";
|
|
return nullptr;
|
|
}
|
|
|
|
return host_snapshot;
|
|
}
|
|
|
|
uint32_t TestGLOnscreenOnlySurface::GetWindowFBOId() const {
|
|
return 0u;
|
|
}
|
|
|
|
TestGLSurface::TestGLSurface(DlISize surface_size)
|
|
: TestGLSurface(std::make_shared<TestEGLContext>(), surface_size) {}
|
|
|
|
TestGLSurface::TestGLSurface(std::shared_ptr<TestEGLContext> egl_context,
|
|
DlISize surface_size)
|
|
: TestGLOnscreenOnlySurface(std::move(egl_context), surface_size) {
|
|
{
|
|
const EGLint offscreen_surface_attributes[] = {
|
|
EGL_WIDTH, 1, //
|
|
EGL_HEIGHT, 1, //
|
|
EGL_NONE,
|
|
};
|
|
offscreen_surface_ = ::eglCreatePbufferSurface(
|
|
egl_context_->display, // display connection
|
|
egl_context_->config, // config
|
|
offscreen_surface_attributes // surface attributes
|
|
);
|
|
FML_CHECK(offscreen_surface_ != EGL_NO_SURFACE) << GetEGLError();
|
|
}
|
|
}
|
|
|
|
TestGLSurface::~TestGLSurface() {
|
|
auto result = ::eglDestroySurface(egl_context_->display, offscreen_surface_);
|
|
FML_CHECK(result == EGL_TRUE) << GetEGLError();
|
|
}
|
|
|
|
bool TestGLSurface::MakeResourceCurrent() {
|
|
auto result =
|
|
::eglMakeCurrent(egl_context_->display, offscreen_surface_,
|
|
offscreen_surface_, egl_context_->offscreen_context);
|
|
|
|
if (result == EGL_FALSE) {
|
|
FML_LOG(ERROR) << "Could not make the resource context current. "
|
|
<< GetEGLError();
|
|
}
|
|
|
|
return result == EGL_TRUE;
|
|
}
|
|
|
|
} // namespace flutter::testing
|