提交 df9e9560 编写于 作者: C Chinmay Garde 提交者: GitHub

Allow plugging in a software backend for rendering in the shell. (#3404)

上级 98e0091f
......@@ -25,6 +25,7 @@ struct Settings {
bool enable_dart_profiling = false;
bool use_test_fonts = false;
bool dart_non_checked_mode = false;
bool force_software_rendering = false;
std::string aot_snapshot_path;
std::string aot_vm_snapshot_data_filename;
std::string aot_vm_snapshot_instr_filename;
......
# Copyright 2017 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
source_set("fml") {
public_deps = []
if (is_ios || is_mac) {
public_deps += [ "platform/darwin" ]
}
}
# Copyright 2017 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
source_set("darwin") {
visibility = [ "//flutter/fml" ]
sources = [
"cf_utils.cc",
"cf_utils.h",
]
deps = [
"//lib/ftl",
]
libs = [ "CoreFoundation.framework" ]
}
// Copyright 2017 The Chromium 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/fml/platform/darwin/cf_utils.h"
namespace fml {
//
} // namespace fml
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_FML_PLATFORM_DARWIN_CF_UTILS_H_
#define FLUTTER_FML_PLATFORM_DARWIN_CF_UTILS_H_
#include <CoreFoundation/CoreFoundation.h>
#include "lib/ftl/macros.h"
namespace fml {
template <class T>
class CFRef {
public:
CFRef() : instance_(nullptr) {}
CFRef(T instance) : instance_(instance) {}
~CFRef() {
if (instance_ != nullptr) {
CFRelease(instance_);
}
instance_ = nullptr;
}
operator T() const { return instance_; }
operator bool() const { return instance_ != nullptr; }
private:
T instance_;
FTL_DISALLOW_COPY_AND_ASSIGN(CFRef);
};
} // namespace fml
#endif // FLUTTER_FML_PLATFORM_DARWIN_CF_UTILS_H_
......@@ -185,6 +185,9 @@ void Shell::InitStandalone(std::string icu_data_path,
settings.trace_startup =
command_line.HasSwitch(FlagForSwitch(Switch::TraceStartup));
settings.force_software_rendering =
command_line.HasSwitch(FlagForSwitch(Switch::ForceSoftwareRendering));
settings.aot_snapshot_path =
command_line.GetSwitchValueASCII(FlagForSwitch(Switch::AotSnapshotPath));
settings.aot_vm_snapshot_data_filename = command_line.GetSwitchValueASCII(
......
......@@ -17,7 +17,7 @@ SurfaceFrame::SurfaceFrame(sk_sp<SkSurface> surface,
SurfaceFrame::~SurfaceFrame() {
if (submit_callback_) {
// Dropping without a Submit.
submit_callback_(nullptr);
submit_callback_(*this, nullptr);
}
}
......@@ -35,12 +35,16 @@ SkCanvas* SurfaceFrame::SkiaCanvas() {
return surface_ != nullptr ? surface_->getCanvas() : nullptr;
}
sk_sp<SkSurface> SurfaceFrame::SkiaSurface() const {
return surface_;
}
bool SurfaceFrame::PerformSubmit() {
if (submit_callback_ == nullptr) {
return false;
}
if (submit_callback_(SkiaCanvas())) {
if (submit_callback_(*this, SkiaCanvas())) {
return true;
}
......
......@@ -17,7 +17,8 @@ namespace shell {
/// rendering API. A frame may only be sumitted once.
class SurfaceFrame {
public:
using SubmitCallback = std::function<bool(SkCanvas* canvas)>;
using SubmitCallback =
std::function<bool(const SurfaceFrame& surface_frame, SkCanvas* canvas)>;
SurfaceFrame(sk_sp<SkSurface> surface, SubmitCallback submit_callback);
......@@ -27,6 +28,8 @@ class SurfaceFrame {
SkCanvas* SkiaCanvas();
sk_sp<SkSurface> SkiaSurface() const;
private:
bool submitted_;
sk_sp<SkSurface> surface_;
......
......@@ -93,6 +93,10 @@ DEF_SWITCH(DartNonCheckedMode,
"precompiled and checked mode is unsupported. However, this flag "
"may be specified if the user wishes to run in the debug product "
"mode (i.e. with JIT or DBC) with checked mode off.")
DEF_SWITCH(ForceSoftwareRendering,
"force-software-rendering",
"On platforms where it is supported (only iOS simulator currently), "
"the shell will attempt to use the software backend for rendering.")
DEF_SWITCHES_END
void PrintUsage(const std::string& executable_name);
......
......@@ -10,6 +10,8 @@ source_set("gpu") {
"gpu_rasterizer.h",
"gpu_surface_gl.cc",
"gpu_surface_gl.h",
"gpu_surface_software.cc",
"gpu_surface_software.h",
]
if (shell_enable_vulkan) {
......@@ -31,8 +33,6 @@ source_set("gpu") {
]
if (shell_enable_vulkan) {
deps += [
"//flutter/vulkan",
]
deps += [ "//flutter/vulkan" ]
}
}
......@@ -84,7 +84,8 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceGL::AcquireFrame(const SkISize& size) {
auto weak_this = weak_factory_.GetWeakPtr();
SurfaceFrame::SubmitCallback submit_callback = [weak_this](SkCanvas* canvas) {
SurfaceFrame::SubmitCallback submit_callback = [weak_this](
const SurfaceFrame& surface_frame, SkCanvas* canvas) {
return weak_this ? weak_this->PresentSurface(canvas) : false;
};
......
// Copyright 2017 The Chromium 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/shell/gpu/gpu_surface_software.h"
#include <memory>
#include "lib/ftl/logging.h"
namespace shell {
GPUSurfaceSoftware::GPUSurfaceSoftware(GPUSurfaceSoftwareDelegate* delegate)
: delegate_(delegate), weak_factory_(this) {}
GPUSurfaceSoftware::~GPUSurfaceSoftware() = default;
bool GPUSurfaceSoftware::Setup() {
return IsValid();
}
bool GPUSurfaceSoftware::IsValid() {
return delegate_ != nullptr;
}
std::unique_ptr<SurfaceFrame> GPUSurfaceSoftware::AcquireFrame(
const SkISize& size) {
if (!IsValid()) {
return nullptr;
}
auto backing_store = delegate_->AcquireBackingStore(size);
if (backing_store == nullptr) {
return nullptr;
}
if (size != SkISize::Make(backing_store->width(), backing_store->height())) {
return nullptr;
}
SurfaceFrame::SubmitCallback
on_submit = [self = weak_factory_.GetWeakPtr()](
const SurfaceFrame& surface_frame, SkCanvas* canvas)
->bool {
// If the surface itself went away, there is nothing more to do.
if (!self || !self->IsValid() || canvas == nullptr) {
return false;
}
canvas->flush();
return self->delegate_->PresentBackingStore(surface_frame.SkiaSurface());
};
return std::make_unique<SurfaceFrame>(backing_store, on_submit);
}
GrContext* GPUSurfaceSoftware::GetContext() {
// The is no GrContext associated with a software surface.
return nullptr;
}
} // namespace shell
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_GPU_GPU_SURFACE_SOFTWARE_H_
#define FLUTTER_SHELL_GPU_GPU_SURFACE_SOFTWARE_H_
#include "flutter/shell/common/surface.h"
#include "lib/ftl/macros.h"
#include "lib/ftl/memory/weak_ptr.h"
#include "third_party/skia/include/core/SkSurface.h"
namespace shell {
class GPUSurfaceSoftwareDelegate {
public:
virtual sk_sp<SkSurface> AcquireBackingStore(const SkISize& size) = 0;
virtual bool PresentBackingStore(sk_sp<SkSurface> backing_store) = 0;
};
class GPUSurfaceSoftware : public Surface {
public:
GPUSurfaceSoftware(GPUSurfaceSoftwareDelegate* delegate);
~GPUSurfaceSoftware() override;
bool Setup() override;
bool IsValid() override;
std::unique_ptr<SurfaceFrame> AcquireFrame(const SkISize& size) override;
GrContext* GetContext() override;
private:
GPUSurfaceSoftwareDelegate* delegate_;
ftl::WeakPtrFactory<GPUSurfaceSoftware> weak_factory_;
FTL_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceSoftware);
};
} // namespace shell
#endif // FLUTTER_SHELL_GPU_GPU_SURFACE_SOFTWARE_H_
......@@ -6,6 +6,7 @@
#define FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_SURFACE_H_
#include <memory>
#include "flutter/shell/common/platform_view.h"
#include "flutter/shell/common/surface.h"
#include "flutter/shell/platform/android/android_native_window.h"
......
......@@ -22,6 +22,7 @@ source_set("common") {
"//dart/runtime:libdart",
"//flutter/common",
"//flutter/flow",
"//flutter/fml",
"//flutter/runtime",
"//flutter/shell/common",
"//flutter/shell/gpu",
......
......@@ -47,6 +47,14 @@ shared_library("flutter_framework_dylib") {
"framework/Source/platform_message_router.mm",
"framework/Source/vsync_waiter_ios.h",
"framework/Source/vsync_waiter_ios.mm",
"ios_gl_context.h",
"ios_gl_context.mm",
"ios_surface.h",
"ios_surface.mm",
"ios_surface_gl.h",
"ios_surface_gl.mm",
"ios_surface_software.h",
"ios_surface_software.mm",
"platform_view_ios.h",
"platform_view_ios.mm",
]
......@@ -55,6 +63,7 @@ shared_library("flutter_framework_dylib") {
"//base:base",
"//dart/runtime:libdart",
"//flutter/flow",
"//flutter/fml",
"//flutter/glue",
"//flutter/lib/ui",
"//flutter/shell/common",
......
......@@ -3,6 +3,8 @@
// found in the LICENSE file.
#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h"
#include "flutter/common/settings.h"
#include "flutter/common/threads.h"
#include "flutter/flow/layers/layer_tree.h"
#include "flutter/shell/common/rasterizer.h"
......@@ -17,19 +19,25 @@
@implementation FlutterView
- (void)layoutSubviews {
CGFloat screenScale = [UIScreen mainScreen].scale;
CAEAGLLayer* layer = reinterpret_cast<CAEAGLLayer*>(self.layer);
layer.allowsGroupOpacity = YES;
layer.opaque = YES;
layer.contentsScale = screenScale;
layer.rasterizationScale = screenScale;
if ([self.layer isKindOfClass:[CAEAGLLayer class]]) {
CAEAGLLayer* layer = reinterpret_cast<CAEAGLLayer*>(self.layer);
layer.allowsGroupOpacity = YES;
layer.opaque = YES;
CGFloat screenScale = [UIScreen mainScreen].scale;
layer.contentsScale = screenScale;
layer.rasterizationScale = screenScale;
}
[super layoutSubviews];
}
+ (Class)layerClass {
#if TARGET_IPHONE_SIMULATOR
return blink::Settings::Get().force_software_rendering ? [CALayer class]
: [CAEAGLLayer class];
#else // TARGET_IPHONE_SIMULATOR
return [CAEAGLLayer class];
#endif // TARGET_IPHONE_SIMULATOR
}
- (BOOL)enableInputClicksWhenVisible {
......
......@@ -10,8 +10,6 @@
#include "base/mac/scoped_nsobject.h"
#include "base/strings/sys_string_conversions.h"
#include "flutter/common/threads.h"
#include "flutter/shell/gpu/gpu_rasterizer.h"
#include "flutter/shell/gpu/gpu_surface_gl.h"
#include "flutter/shell/platform/darwin/common/platform_mac.h"
#include "flutter/shell/platform/darwin/common/string_conversions.h"
#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h"
......@@ -473,8 +471,7 @@ static inline PointerChangeMapperPhase PointerChangePhaseFromUITouchPhase(
CHECK(_platformView != nullptr);
if (appeared) {
_platformView->NotifyCreated(
std::make_unique<shell::GPUSurfaceGL>(_platformView.get()));
_platformView->NotifyCreated();
} else {
_platformView->NotifyDestroyed();
}
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_GL_CONTEXT_H_
#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_GL_CONTEXT_H_
#import <OpenGLES/EAGL.h>
#import <OpenGLES/ES2/gl.h>
#import <OpenGLES/ES2/glext.h>
#import <QuartzCore/CAEAGLLayer.h>
#include "base/mac/scoped_nsobject.h"
#include "flutter/shell/common/platform_view.h"
#include "lib/ftl/macros.h"
namespace shell {
class IOSGLContext {
public:
IOSGLContext(PlatformView::SurfaceConfig config, CAEAGLLayer* layer);
~IOSGLContext();
bool IsValid() const;
bool PresentRenderBuffer() const;
GLuint framebuffer() const { return framebuffer_; }
bool UpdateStorageSizeIfNecessary();
bool MakeCurrent();
bool ResourceMakeCurrent();
private:
base::scoped_nsobject<CAEAGLLayer> layer_;
base::scoped_nsobject<EAGLContext> context_;
base::scoped_nsobject<EAGLContext> resource_context_;
GLuint framebuffer_;
GLuint colorbuffer_;
GLuint depthbuffer_;
GLuint stencilbuffer_;
GLuint depth_stencil_packed_buffer_;
GLint storage_size_width_;
GLint storage_size_height_;
bool valid_;
FTL_DISALLOW_COPY_AND_ASSIGN(IOSGLContext);
};
} // namespace shell
#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_GL_CONTEXT_H_
// Copyright 2017 The Chromium 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 "base/mac/scoped_nsautorelease_pool.h"
#include "flutter/shell/platform/darwin/ios/ios_gl_context.h"
namespace shell {
#define VERIFY(x) \
if (!(x)) { \
FTL_DLOG(ERROR) << "Failed: " #x; \
return; \
};
IOSGLContext::IOSGLContext(PlatformView::SurfaceConfig config,
CAEAGLLayer* layer)
: layer_([layer retain]),
context_([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]),
resource_context_([[EAGLContext alloc]
initWithAPI:kEAGLRenderingAPIOpenGLES2
sharegroup:context_.get().sharegroup]),
framebuffer_(GL_NONE),
colorbuffer_(GL_NONE),
depthbuffer_(GL_NONE),
stencilbuffer_(GL_NONE),
depth_stencil_packed_buffer_(GL_NONE),
storage_size_width_(0),
storage_size_height_(0),
valid_(false) {
base::mac::ScopedNSAutoreleasePool pool;
VERIFY(layer_ != nullptr);
VERIFY(context_ != nullptr);
VERIFY(resource_context_ != nullptr);
bool context_current = [EAGLContext setCurrentContext:context_];
VERIFY(context_current);
VERIFY(glGetError() == GL_NO_ERROR);
// Generate the framebuffer
glGenFramebuffers(1, &framebuffer_);
VERIFY(glGetError() == GL_NO_ERROR);
VERIFY(framebuffer_ != GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
VERIFY(glGetError() == GL_NO_ERROR);
// Setup color attachment
glGenRenderbuffers(1, &colorbuffer_);
VERIFY(colorbuffer_ != GL_NONE);
glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_);
VERIFY(glGetError() == GL_NO_ERROR);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER, colorbuffer_);
VERIFY(glGetError() == GL_NO_ERROR);
// On iOS, if both depth and stencil attachments are requested, we are
// required to create a single renderbuffer that acts as both.
auto requires_packed = (config.depth_bits != 0) && (config.stencil_bits != 0);
if (requires_packed) {
glGenRenderbuffers(1, &depth_stencil_packed_buffer_);
glBindRenderbuffer(GL_RENDERBUFFER, depth_stencil_packed_buffer_);
VERIFY(depth_stencil_packed_buffer_ != GL_NONE);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, depth_stencil_packed_buffer_);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, depth_stencil_packed_buffer_);
VERIFY(depth_stencil_packed_buffer_ != GL_NONE);
} else {
// Setup the depth attachment if necessary
if (config.depth_bits != 0) {
glGenRenderbuffers(1, &depthbuffer_);
VERIFY(depthbuffer_ != GL_NONE);
glBindRenderbuffer(GL_RENDERBUFFER, depthbuffer_);
VERIFY(glGetError() == GL_NO_ERROR);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, depthbuffer_);
VERIFY(glGetError() == GL_NO_ERROR);
}
// Setup the stencil attachment if necessary
if (config.stencil_bits != 0) {
glGenRenderbuffers(1, &stencilbuffer_);
VERIFY(stencilbuffer_ != GL_NONE);
glBindRenderbuffer(GL_RENDERBUFFER, stencilbuffer_);
VERIFY(glGetError() == GL_NO_ERROR);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, stencilbuffer_);
VERIFY(glGetError() == GL_NO_ERROR);
}
}
// The default is RGBA
NSString* drawableColorFormat = kEAGLColorFormatRGBA8;
if (config.red_bits <= 5 && config.green_bits <= 6 && config.blue_bits <= 5 &&
config.alpha_bits == 0) {
drawableColorFormat = kEAGLColorFormatRGB565;
}
layer_.get().drawableProperties = @{
kEAGLDrawablePropertyColorFormat : drawableColorFormat,
kEAGLDrawablePropertyRetainedBacking : @(NO),
};
valid_ = true;
}
IOSGLContext::~IOSGLContext() {
DCHECK(glGetError() == GL_NO_ERROR);
// Deletes on GL_NONEs are ignored
glDeleteFramebuffers(1, &framebuffer_);
glDeleteRenderbuffers(1, &colorbuffer_);
glDeleteRenderbuffers(1, &depthbuffer_);
glDeleteRenderbuffers(1, &stencilbuffer_);
glDeleteRenderbuffers(1, &depth_stencil_packed_buffer_);
DCHECK(glGetError() == GL_NO_ERROR);
}
bool IOSGLContext::IsValid() const {
return valid_;
}
bool IOSGLContext::PresentRenderBuffer() const {
base::mac::ScopedNSAutoreleasePool pool;
const GLenum discards[] = {
GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT,
};
glDiscardFramebufferEXT(GL_FRAMEBUFFER, sizeof(discards) / sizeof(GLenum),
discards);
glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_);
return [[EAGLContext currentContext] presentRenderbuffer:GL_RENDERBUFFER];
}
bool IOSGLContext::UpdateStorageSizeIfNecessary() {
const CGSize layer_size = [layer_.get() bounds].size;
const GLint size_width = layer_size.width;
const GLint size_height = layer_size.height;
if (size_width == storage_size_width_ &&
size_height == storage_size_height_) {
// Nothing to since the stoage size is already consistent with the layer.
return true;
}
if (![EAGLContext setCurrentContext:context_]) {
return false;
}
DCHECK(glGetError() == GL_NO_ERROR);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_);
DCHECK(glGetError() == GL_NO_ERROR);
if (![context_.get() renderbufferStorage:GL_RENDERBUFFER
fromDrawable:layer_.get()]) {
return false;
}
GLint width = 0;
GLint height = 0;
bool rebind_color_buffer = false;
if (depthbuffer_ != GL_NONE || stencilbuffer_ != GL_NONE ||
depth_stencil_packed_buffer_ != GL_NONE) {
// Fetch the dimensions of the color buffer whose backing was just updated
// so that backing of the attachments can be updated
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH,
&width);
DCHECK(glGetError() == GL_NO_ERROR);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT,
&height);
DCHECK(glGetError() == GL_NO_ERROR);
rebind_color_buffer = true;
}
if (depth_stencil_packed_buffer_ != GL_NONE) {
glBindRenderbuffer(GL_RENDERBUFFER, depth_stencil_packed_buffer_);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, width,
height);
DCHECK(glGetError() == GL_NO_ERROR);
}
if (depthbuffer_ != GL_NONE) {
glBindRenderbuffer(GL_RENDERBUFFER, depthbuffer_);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
DCHECK(glGetError() == GL_NO_ERROR);
}
if (stencilbuffer_ != GL_NONE) {
glBindRenderbuffer(GL_RENDERBUFFER, stencilbuffer_);
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height);
DCHECK(glGetError() == GL_NO_ERROR);
}
if (rebind_color_buffer) {
glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_);
DCHECK(glGetError() == GL_NO_ERROR);
}
storage_size_width_ = width;
storage_size_height_ = height;
DCHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
return true;
}
bool IOSGLContext::MakeCurrent() {
base::mac::ScopedNSAutoreleasePool pool;
return UpdateStorageSizeIfNecessary() &&
[EAGLContext setCurrentContext:context_.get()];
}
bool IOSGLContext::ResourceMakeCurrent() {
base::mac::ScopedNSAutoreleasePool pool;
return [EAGLContext setCurrentContext:resource_context_.get()];
}
} // namespace shell
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_SURFACE_H_
#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_SURFACE_H_
#include "base/mac/scoped_nsobject.h"
#include "flutter/shell/common/platform_view.h"
#include "lib/ftl/macros.h"
@class CALayer;
namespace shell {
class IOSSurface {
public:
static std::unique_ptr<IOSSurface> Create(
PlatformView::SurfaceConfig surface_config,
CALayer* layer);
IOSSurface(PlatformView::SurfaceConfig surface_config, CALayer* layer);
CALayer* GetLayer() const;
PlatformView::SurfaceConfig GetSurfaceConfig() const;
virtual ~IOSSurface();
virtual bool IsValid() const = 0;
virtual bool ResourceContextMakeCurrent() = 0;
virtual void UpdateStorageSizeIfNecessary() = 0;
virtual std::unique_ptr<Surface> CreateGPUSurface() = 0;
public:
PlatformView::SurfaceConfig surface_config_;
base::scoped_nsobject<CALayer> layer_;
FTL_DISALLOW_COPY_AND_ASSIGN(IOSSurface);
};
} // namespace shell
#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_SURFACE_H_
// Copyright 2017 The Chromium 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/shell/platform/darwin/ios/ios_surface.h"
#include <flutter/shell/platform/darwin/ios/ios_surface_gl.h>
#include <flutter/shell/platform/darwin/ios/ios_surface_software.h>
#include <memory>
@class CALayer;
@class CAEAGLLayer;
namespace shell {
std::unique_ptr<IOSSurface> IOSSurface::Create(
PlatformView::SurfaceConfig surface_config,
CALayer* layer) {
// Check if we can use OpenGL.
if ([layer isKindOfClass:[CAEAGLLayer class]]) {
return std::make_unique<IOSSurfaceGL>(
surface_config, reinterpret_cast<CAEAGLLayer*>(layer));
}
// If we ever support the metal rendering API, a check for CAMetalLayer would
// go here.
// Finally, fallback to software rendering.
return std::make_unique<IOSSurfaceSoftware>(surface_config, layer);
}
IOSSurface::IOSSurface(PlatformView::SurfaceConfig surface_config,
CALayer* layer)
: surface_config_(surface_config), layer_([layer retain]) {}
IOSSurface::~IOSSurface() = default;
CALayer* IOSSurface::GetLayer() const {
return layer_;
}
PlatformView::SurfaceConfig IOSSurface::GetSurfaceConfig() const {
return surface_config_;
}
} // namespace shell
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_SURFACE_GL_H_
#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_SURFACE_GL_H_
#include "flutter/shell/gpu/gpu_surface_gl.h"
#include "flutter/shell/platform/darwin/ios/ios_gl_context.h"
#include "flutter/shell/platform/darwin/ios/ios_surface.h"
#include "lib/ftl/macros.h"
@class CAEAGLLayer;
namespace shell {
class IOSSurfaceGL : public IOSSurface, public GPUSurfaceGLDelegate {
public:
IOSSurfaceGL(PlatformView::SurfaceConfig surface_config, CAEAGLLayer* layer);
~IOSSurfaceGL() override;
bool IsValid() const override;
bool ResourceContextMakeCurrent() override;
void UpdateStorageSizeIfNecessary() override;
std::unique_ptr<Surface> CreateGPUSurface() override;
bool GLContextMakeCurrent() override;
bool GLContextClearCurrent() override;
bool GLContextPresent() override;
intptr_t GLContextFBO() const override;
private:
IOSGLContext context_;
FTL_DISALLOW_COPY_AND_ASSIGN(IOSSurfaceGL);
};
} // namespace shell
#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_SURFACE_GL_H_
// Copyright 2017 The Chromium 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/shell/platform/darwin/ios/ios_surface_gl.h"
#include "flutter/shell/gpu/gpu_surface_gl.h"
namespace shell {
IOSSurfaceGL::IOSSurfaceGL(PlatformView::SurfaceConfig surface_config,
CAEAGLLayer* layer)
: IOSSurface(surface_config, reinterpret_cast<CALayer*>(layer)),
context_(surface_config, layer) {}
IOSSurfaceGL::~IOSSurfaceGL() = default;
bool IOSSurfaceGL::IsValid() const {
return context_.IsValid();
}
bool IOSSurfaceGL::ResourceContextMakeCurrent() {
return IsValid() ? context_.ResourceMakeCurrent() : false;
}
void IOSSurfaceGL::UpdateStorageSizeIfNecessary() {
if (IsValid()) {
context_.UpdateStorageSizeIfNecessary();
}
}
std::unique_ptr<Surface> IOSSurfaceGL::CreateGPUSurface() {
return std::make_unique<GPUSurfaceGL>(this);
}
intptr_t IOSSurfaceGL::GLContextFBO() const {
return IsValid() ? context_.framebuffer() : GL_NONE;
}
bool IOSSurfaceGL::GLContextMakeCurrent() {
return IsValid() ? context_.MakeCurrent() : false;
}
bool IOSSurfaceGL::GLContextClearCurrent() {
[EAGLContext setCurrentContext:nil];
return true;
}
bool IOSSurfaceGL::GLContextPresent() {
TRACE_EVENT0("flutter", "IOSSurfaceGL::GLContextPresent");
return IsValid() ? context_.PresentRenderBuffer() : false;
}
} // namespace shell
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_SURFACE_SOFTWARE_H_
#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_SURFACE_SOFTWARE_H_
#include "flutter/shell/gpu/gpu_surface_software.h"
#include "flutter/shell/platform/darwin/ios/ios_surface.h"
#include "lib/ftl/macros.h"
namespace shell {
class IOSSurfaceSoftware : public IOSSurface,
public GPUSurfaceSoftwareDelegate {
public:
IOSSurfaceSoftware(PlatformView::SurfaceConfig surface_config,
CALayer* layer);
~IOSSurfaceSoftware() override;
bool IsValid() const override;
bool ResourceContextMakeCurrent() override;
void UpdateStorageSizeIfNecessary() override;
std::unique_ptr<Surface> CreateGPUSurface() override;
sk_sp<SkSurface> AcquireBackingStore(const SkISize& size) override;
bool PresentBackingStore(sk_sp<SkSurface> backing_store) override;
private:
sk_sp<SkSurface> sk_surface_;
FTL_DISALLOW_COPY_AND_ASSIGN(IOSSurfaceSoftware);
};
} // namespace shell
#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_SURFACE_SOFTWARE_H_
// Copyright 2017 The Chromium 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/shell/platform/darwin/ios/ios_surface_software.h"
#include <QuartzCore/CALayer.h>
#include <memory>
#include "flutter/fml/platform/darwin/cf_utils.h"
#include "lib/ftl/logging.h"
#include "third_party/skia/include/utils/mac/SkCGUtils.h"
namespace shell {
IOSSurfaceSoftware::IOSSurfaceSoftware(
PlatformView::SurfaceConfig surface_config,
CALayer* layer)
: IOSSurface(surface_config, layer) {
UpdateStorageSizeIfNecessary();
}
IOSSurfaceSoftware::~IOSSurfaceSoftware() = default;
bool IOSSurfaceSoftware::IsValid() const {
return GetLayer() != nullptr;
}
bool IOSSurfaceSoftware::ResourceContextMakeCurrent() {
return false;
}
void IOSSurfaceSoftware::UpdateStorageSizeIfNecessary() {
// Nothing to do here. We don't need an external entity to tell us when our
// backing store needs to be updated. Instead, we let the frame tell us its
// size so we can update to match. This method was added to work around
// Android oddities.
}
std::unique_ptr<Surface> IOSSurfaceSoftware::CreateGPUSurface() {
if (!IsValid()) {
return nullptr;
}
auto surface = std::make_unique<GPUSurfaceSoftware>(this);
if (!surface->IsValid()) {
return nullptr;
}
return surface;
}
sk_sp<SkSurface> IOSSurfaceSoftware::AcquireBackingStore(const SkISize& size) {
if (!IsValid()) {
return nullptr;
}
if (sk_surface_ != nullptr &&
SkISize::Make(sk_surface_->width(), sk_surface_->height()) == size) {
// The old and new surface sizes are the same. Nothing to do here.
return sk_surface_;
}
sk_surface_ = SkSurface::MakeRasterN32Premul(
size.fWidth, size.fHeight, nullptr /* SkSurfaceProps as out */);
return sk_surface_;
}
bool IOSSurfaceSoftware::PresentBackingStore(sk_sp<SkSurface> backing_store) {
if (!IsValid() || backing_store == nullptr) {
return false;
}
SkPixmap pixmap;
if (!backing_store->peekPixels(&pixmap)) {
return false;
}
uint64_t expected_pixmap_data_size = pixmap.width() * pixmap.height() * 4;
if (expected_pixmap_data_size != pixmap.getSize64()) {
return false;
}
fml::CFRef<CGColorSpaceRef> colorspace(CGColorSpaceCreateDeviceRGB());
fml::CFRef<CGContextRef> bitmap(CGBitmapContextCreate(
const_cast<uint32_t*>(pixmap.addr32()), // data managed pixmap
pixmap.width(), // width
pixmap.height(), // height
8, // bits per component
4 * pixmap.width(), // bytes per row
colorspace, // colorspace
kCGImageAlphaPremultipliedLast // bitmap info
));
if (!bitmap) {
return false;
}
fml::CFRef<CGImageRef> image(CGBitmapContextCreateImage(bitmap));
if (!image) {
return false;
}
[GetLayer() setContents:reinterpret_cast<id>(static_cast<CGImageRef>(image))];
return true;
}
} // namespace shell
......@@ -9,25 +9,25 @@
#include "base/mac/scoped_nsobject.h"
#include "flutter/shell/common/platform_view.h"
#include "flutter/shell/gpu/gpu_surface_gl.h"
#include "flutter/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h"
#include "flutter/shell/platform/darwin/ios/framework/Source/platform_message_router.h"
#include "flutter/shell/platform/darwin/ios/ios_surface.h"
#include "lib/ftl/macros.h"
#include "lib/ftl/memory/weak_ptr.h"
@class CAEAGLLayer;
@class CALayer;
@class UIView;
namespace shell {
class IOSGLContext;
class PlatformViewIOS : public PlatformView, public GPUSurfaceGLDelegate {
class PlatformViewIOS : public PlatformView {
public:
explicit PlatformViewIOS(CAEAGLLayer* layer);
explicit PlatformViewIOS(CALayer* layer);
~PlatformViewIOS() override;
void NotifyCreated();
void ToggleAccessibility(UIView* view, bool enabled);
PlatformMessageRouter& platform_message_router() {
......@@ -42,14 +42,6 @@ class PlatformViewIOS : public PlatformView, public GPUSurfaceGLDelegate {
bool ResourceContextMakeCurrent() override;
bool GLContextMakeCurrent() override;
bool GLContextClearCurrent() override;
bool GLContextPresent() override;
intptr_t GLContextFBO() const override;
void HandlePlatformMessage(
ftl::RefPtr<blink::PlatformMessage> message) override;
......@@ -60,7 +52,7 @@ class PlatformViewIOS : public PlatformView, public GPUSurfaceGLDelegate {
const std::string& packages) override;
private:
std::unique_ptr<IOSGLContext> context_;
std::unique_ptr<IOSSurface> ios_surface_;
PlatformMessageRouter platform_message_router_;
std::unique_ptr<AccessibilityBridge> accessibility_bridge_;
ftl::WeakPtrFactory<PlatformViewIOS> weak_factory_;
......
......@@ -4,10 +4,8 @@
#include "flutter/shell/platform/darwin/ios/platform_view_ios.h"
#import <OpenGLES/EAGL.h>
#import <OpenGLES/ES2/gl.h>
#import <OpenGLES/ES2/glext.h>
#import <QuartzCore/CAEAGLLayer.h>
#include <utility>
#include "base/mac/scoped_nsautorelease_pool.h"
......@@ -20,261 +18,10 @@
namespace shell {
struct GLintSize {
GLint width;
GLint height;
GLintSize() : width(0), height(0) {}
GLintSize(GLint w, GLint h) : width(w), height(h) {}
GLintSize(CGSize size)
: width(static_cast<GLint>(size.width)),
height(static_cast<GLint>(size.height)) {}
bool operator==(const GLintSize& other) const {
return width == other.width && height == other.height;
}
};
class IOSGLContext {
public:
IOSGLContext(PlatformView::SurfaceConfig config, CAEAGLLayer* layer)
: layer_([layer retain]),
context_([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]),
resource_context_([[EAGLContext alloc]
initWithAPI:kEAGLRenderingAPIOpenGLES2
sharegroup:context_.get().sharegroup]),
framebuffer_(GL_NONE),
colorbuffer_(GL_NONE),
depthbuffer_(GL_NONE),
stencilbuffer_(GL_NONE),
depth_stencil_packed_buffer_(GL_NONE) {
base::mac::ScopedNSAutoreleasePool pool;
CHECK(layer_ != nullptr);
CHECK(context_ != nullptr);
CHECK(resource_context_ != nullptr);
bool context_current = [EAGLContext setCurrentContext:context_];
DCHECK(context_current);
DCHECK(glGetError() == GL_NO_ERROR);
// Generate the framebuffer
glGenFramebuffers(1, &framebuffer_);
DCHECK(glGetError() == GL_NO_ERROR);
DCHECK(framebuffer_ != GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
DCHECK(glGetError() == GL_NO_ERROR);
// Setup color attachment
glGenRenderbuffers(1, &colorbuffer_);
DCHECK(colorbuffer_ != GL_NONE);
glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_);
DCHECK(glGetError() == GL_NO_ERROR);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER, colorbuffer_);
DCHECK(glGetError() == GL_NO_ERROR);
// On iOS, if both depth and stencil attachments are requested, we are
// required to create a single renderbuffer that acts as both.
auto requires_packed =
(config.depth_bits != 0) && (config.stencil_bits != 0);
if (requires_packed) {
glGenRenderbuffers(1, &depth_stencil_packed_buffer_);
glBindRenderbuffer(GL_RENDERBUFFER, depth_stencil_packed_buffer_);
DCHECK(depth_stencil_packed_buffer_ != GL_NONE);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, depth_stencil_packed_buffer_);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, depth_stencil_packed_buffer_);
DCHECK(depth_stencil_packed_buffer_ != GL_NONE);
} else {
// Setup the depth attachment if necessary
if (config.depth_bits != 0) {
glGenRenderbuffers(1, &depthbuffer_);
DCHECK(depthbuffer_ != GL_NONE);
glBindRenderbuffer(GL_RENDERBUFFER, depthbuffer_);
DCHECK(glGetError() == GL_NO_ERROR);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, depthbuffer_);
DCHECK(glGetError() == GL_NO_ERROR);
}
// Setup the stencil attachment if necessary
if (config.stencil_bits != 0) {
glGenRenderbuffers(1, &stencilbuffer_);
DCHECK(stencilbuffer_ != GL_NONE);
glBindRenderbuffer(GL_RENDERBUFFER, stencilbuffer_);
DCHECK(glGetError() == GL_NO_ERROR);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, stencilbuffer_);
DCHECK(glGetError() == GL_NO_ERROR);
}
}
// The default is RGBA
NSString* drawableColorFormat = kEAGLColorFormatRGBA8;
if (config.red_bits <= 5 && config.green_bits <= 6 &&
config.blue_bits <= 5 && config.alpha_bits == 0) {
drawableColorFormat = kEAGLColorFormatRGB565;
}
layer_.get().drawableProperties = @{
kEAGLDrawablePropertyColorFormat : drawableColorFormat,
kEAGLDrawablePropertyRetainedBacking : @(NO),
};
}
~IOSGLContext() {
DCHECK(glGetError() == GL_NO_ERROR);
// Deletes on GL_NONEs are ignored
glDeleteFramebuffers(1, &framebuffer_);
glDeleteRenderbuffers(1, &colorbuffer_);
glDeleteRenderbuffers(1, &depthbuffer_);
glDeleteRenderbuffers(1, &stencilbuffer_);
glDeleteRenderbuffers(1, &depth_stencil_packed_buffer_);
DCHECK(glGetError() == GL_NO_ERROR);
}
bool PresentRenderBuffer() const {
base::mac::ScopedNSAutoreleasePool pool;
const GLenum discards[] = {
GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT,
};
glDiscardFramebufferEXT(GL_FRAMEBUFFER, sizeof(discards) / sizeof(GLenum),
discards);
glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_);
return [[EAGLContext currentContext] presentRenderbuffer:GL_RENDERBUFFER];
}
GLuint framebuffer() const { return framebuffer_; }
bool UpdateStorageSizeIfNecessary() {
GLintSize size([layer_.get() bounds].size);
if (size == storage_size_) {
// Nothing to since the stoage size is already consistent with the layer.
return true;
}
if (![EAGLContext setCurrentContext:context_]) {
return false;
}
DCHECK(glGetError() == GL_NO_ERROR);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_);
DCHECK(glGetError() == GL_NO_ERROR);
if (![context_.get() renderbufferStorage:GL_RENDERBUFFER
fromDrawable:layer_.get()]) {
return false;
}
GLint width = 0;
GLint height = 0;
bool rebind_color_buffer = false;
if (depthbuffer_ != GL_NONE || stencilbuffer_ != GL_NONE ||
depth_stencil_packed_buffer_ != GL_NONE) {
// Fetch the dimensions of the color buffer whose backing was just updated
// so that backing of the attachments can be updated
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH,
&width);
DCHECK(glGetError() == GL_NO_ERROR);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT,
&height);
DCHECK(glGetError() == GL_NO_ERROR);
rebind_color_buffer = true;
}
if (depth_stencil_packed_buffer_ != GL_NONE) {
glBindRenderbuffer(GL_RENDERBUFFER, depth_stencil_packed_buffer_);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, width,
height);
DCHECK(glGetError() == GL_NO_ERROR);
}
if (depthbuffer_ != GL_NONE) {
glBindRenderbuffer(GL_RENDERBUFFER, depthbuffer_);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width,
height);
DCHECK(glGetError() == GL_NO_ERROR);
}
if (stencilbuffer_ != GL_NONE) {
glBindRenderbuffer(GL_RENDERBUFFER, stencilbuffer_);
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height);
DCHECK(glGetError() == GL_NO_ERROR);
}
if (rebind_color_buffer) {
glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_);
DCHECK(glGetError() == GL_NO_ERROR);
}
storage_size_ = GLintSize(width, height);
DCHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
return true;
}
bool MakeCurrent() {
base::mac::ScopedNSAutoreleasePool pool;
return UpdateStorageSizeIfNecessary() &&
[EAGLContext setCurrentContext:context_.get()];
}
bool ResourceMakeCurrent() {
base::mac::ScopedNSAutoreleasePool pool;
return [EAGLContext setCurrentContext:resource_context_.get()];
}
private:
base::scoped_nsobject<CAEAGLLayer> layer_;
base::scoped_nsobject<EAGLContext> context_;
base::scoped_nsobject<EAGLContext> resource_context_;
GLuint framebuffer_;
GLuint colorbuffer_;
GLuint depthbuffer_;
GLuint stencilbuffer_;
GLuint depth_stencil_packed_buffer_;
GLintSize storage_size_;
FTL_DISALLOW_COPY_AND_ASSIGN(IOSGLContext);
};
PlatformViewIOS::PlatformViewIOS(CAEAGLLayer* layer)
PlatformViewIOS::PlatformViewIOS(CALayer* layer)
: PlatformView(
std::make_unique<GPURasterizer>(std::make_unique<ProcessInfoMac>())),
context_(std::make_unique<IOSGLContext>(surface_config_, layer)),
ios_surface_(IOSSurface::Create(surface_config_, layer)),
weak_factory_(this) {
CreateEngine();
......@@ -288,6 +35,10 @@ PlatformViewIOS::PlatformViewIOS(CAEAGLLayer* layer)
PlatformViewIOS::~PlatformViewIOS() = default;
void PlatformViewIOS::NotifyCreated() {
PlatformView::NotifyCreated(ios_surface_->CreateGPUSurface());
}
void PlatformViewIOS::ToggleAccessibility(UIView* view, bool enabled) {
if (enabled) {
if (!accessibility_bridge_) {
......@@ -316,38 +67,22 @@ ftl::WeakPtr<PlatformViewIOS> PlatformViewIOS::GetWeakPtr() {
void PlatformViewIOS::UpdateSurfaceSize() {
blink::Threads::Gpu()->PostTask([self = GetWeakPtr()]() {
if (self && self->context_ != nullptr) {
self->context_->UpdateStorageSizeIfNecessary();
if (self && self->ios_surface_ != nullptr) {
self->ios_surface_->UpdateStorageSizeIfNecessary();
}
});
}
VsyncWaiter* PlatformViewIOS::GetVsyncWaiter() {
if (!vsync_waiter_)
if (!vsync_waiter_) {
vsync_waiter_ = std::make_unique<VsyncWaiterIOS>();
}
return vsync_waiter_.get();
}
bool PlatformViewIOS::ResourceContextMakeCurrent() {
return context_ != nullptr ? context_->ResourceMakeCurrent() : false;
}
intptr_t PlatformViewIOS::GLContextFBO() const {
return context_ != nullptr ? context_->framebuffer() : GL_NONE;
}
bool PlatformViewIOS::GLContextMakeCurrent() {
return context_ != nullptr ? context_->MakeCurrent() : false;
}
bool PlatformViewIOS::GLContextClearCurrent() {
[EAGLContext setCurrentContext:nil];
return true;
}
bool PlatformViewIOS::GLContextPresent() {
TRACE_EVENT0("flutter", "PlatformViewIOS::GLContextPresent");
return context_ != nullptr ? context_->PresentRenderBuffer() : false;
return ios_surface_ != nullptr ? ios_surface_->ResourceContextMakeCurrent()
: false;
}
void PlatformViewIOS::UpdateSemantics(
......
......@@ -21148,8 +21148,20 @@ FILE: ../../../flutter/content_handler/vulkan_rasterizer.cc
FILE: ../../../flutter/content_handler/vulkan_rasterizer.h
FILE: ../../../flutter/flow/layers/physical_model_layer.cc
FILE: ../../../flutter/flow/layers/physical_model_layer.h
FILE: ../../../flutter/fml/platform/darwin/cf_utils.cc
FILE: ../../../flutter/fml/platform/darwin/cf_utils.h
FILE: ../../../flutter/shell/gpu/gpu_surface_software.cc
FILE: ../../../flutter/shell/gpu/gpu_surface_software.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/flutter_main_ios.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/flutter_main_ios.mm
FILE: ../../../flutter/shell/platform/darwin/ios/ios_gl_context.h
FILE: ../../../flutter/shell/platform/darwin/ios/ios_gl_context.mm
FILE: ../../../flutter/shell/platform/darwin/ios/ios_surface.h
FILE: ../../../flutter/shell/platform/darwin/ios/ios_surface.mm
FILE: ../../../flutter/shell/platform/darwin/ios/ios_surface_gl.h
FILE: ../../../flutter/shell/platform/darwin/ios/ios_surface_gl.mm
FILE: ../../../flutter/shell/platform/darwin/ios/ios_surface_software.h
FILE: ../../../flutter/shell/platform/darwin/ios/ios_surface_software.mm
FILE: ../../../flutter/vulkan/vulkan_native_surface_magma.cc
FILE: ../../../flutter/vulkan/vulkan_native_surface_magma.h
----------------------------------------------------------------------------------------------------
......@@ -72107,4 +72119,4 @@ freely, subject to the following restrictions:
3. This notice may not be removed or altered from any source distribution.
====================================================================================================
Total license count: 695
31541 of 31541 ██████████ 100% (0 missing licenses) Done.
31553 of 31553 ██████████ 100% (0 missing licenses) Done.
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册