Implement SkGLContext swapBuffers with fence syncs
Improves the GPU measuring accuracy of nanobench by using fence syncs. Fence syncs are very widely supported and available on almost every platform. NO_MERGE_BUILDS BUG=skia: Review URL: https://codereview.chromium.org/1194783003
This commit is contained in:
parent
b607767703
commit
d416a5b10f
@ -79,7 +79,7 @@ DEFINE_int32(overheadLoops, 100000, "Loops to estimate timer overhead.");
|
||||
DEFINE_double(overheadGoal, 0.0001,
|
||||
"Loop until timer overhead is at most this fraction of our measurments.");
|
||||
DEFINE_double(gpuMs, 5, "Target bench time in millseconds for GPU.");
|
||||
DEFINE_int32(gpuFrameLag, 5, "Overestimate of maximum number of frames GPU allows to lag.");
|
||||
DEFINE_int32(gpuFrameLag, 5, "If unknown, estimated maximum number of frames GPU allows to lag.");
|
||||
DEFINE_bool(gpuCompressAlphaMasks, false, "Compress masks generated from falling back to "
|
||||
"software path rendering.");
|
||||
|
||||
@ -144,7 +144,13 @@ struct GPUTarget : public Target {
|
||||
SK_GL(*this->gl, Finish());
|
||||
}
|
||||
|
||||
bool needsFrameTiming() const override { return true; }
|
||||
bool needsFrameTiming(int* maxFrameLag) const override {
|
||||
if (!this->gl->getMaxGpuFrameLag(maxFrameLag)) {
|
||||
// Frame lag is unknown.
|
||||
*maxFrameLag = FLAGS_gpuFrameLag;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool init(SkImageInfo info, Benchmark* bench) override {
|
||||
uint32_t flags = this->config.useDFText ? SkSurfaceProps::kUseDistanceFieldFonts_Flag : 0;
|
||||
SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
|
||||
@ -155,6 +161,10 @@ struct GPUTarget : public Target {
|
||||
if (!this->surface.get()) {
|
||||
return false;
|
||||
}
|
||||
if (!this->gl->fenceSyncSupport()) {
|
||||
SkDebugf("WARNING: GL context for config \"%s\" does not support fence sync. "
|
||||
"Timings might not be accurate.\n", this->config.name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void fillOptions(ResultsWriter* log) override {
|
||||
@ -307,7 +317,8 @@ static int cpu_bench(const double overhead, Target* target, Benchmark* bench, do
|
||||
|
||||
static int gpu_bench(Target* target,
|
||||
Benchmark* bench,
|
||||
double* samples) {
|
||||
double* samples,
|
||||
int maxGpuFrameLag) {
|
||||
// First, figure out how many loops it'll take to get a frame up to FLAGS_gpuMs.
|
||||
int loops = FLAGS_loops;
|
||||
if (kAutoTuneLoops == loops) {
|
||||
@ -321,9 +332,8 @@ static int gpu_bench(Target* target,
|
||||
}
|
||||
loops *= 2;
|
||||
// If the GPU lets frames lag at all, we need to make sure we're timing
|
||||
// _this_ round, not still timing last round. We force this by looping
|
||||
// more times than any reasonable GPU will allow frames to lag.
|
||||
for (int i = 0; i < FLAGS_gpuFrameLag; i++) {
|
||||
// _this_ round, not still timing last round.
|
||||
for (int i = 0; i < maxGpuFrameLag; i++) {
|
||||
elapsed = time(loops, bench, target);
|
||||
}
|
||||
} while (elapsed < FLAGS_gpuMs);
|
||||
@ -340,7 +350,7 @@ static int gpu_bench(Target* target,
|
||||
|
||||
// Pretty much the same deal as the calibration: do some warmup to make
|
||||
// sure we're timing steady-state pipelined frames.
|
||||
for (int i = 0; i < FLAGS_gpuFrameLag; i++) {
|
||||
for (int i = 0; i < maxGpuFrameLag - 1; i++) {
|
||||
time(loops, bench, target);
|
||||
}
|
||||
|
||||
@ -428,6 +438,9 @@ static void create_configs(SkTDArray<Config>* configs) {
|
||||
GPU_CONFIG(nullgpu, kNull_GLContextType, 0, false)
|
||||
#ifdef SK_ANGLE
|
||||
GPU_CONFIG(angle, kANGLE_GLContextType, 0, false)
|
||||
#endif
|
||||
#if SK_MESA
|
||||
GPU_CONFIG(mesa, kMESA_GLContextType, 0, false)
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
@ -1008,9 +1021,10 @@ int nanobench_main() {
|
||||
targets[j]->setup();
|
||||
bench->perCanvasPreDraw(canvas);
|
||||
|
||||
int frameLag;
|
||||
const int loops =
|
||||
targets[j]->needsFrameTiming()
|
||||
? gpu_bench(targets[j], bench.get(), samples.get())
|
||||
targets[j]->needsFrameTiming(&frameLag)
|
||||
? gpu_bench(targets[j], bench.get(), samples.get(), frameLag)
|
||||
: cpu_bench(overhead, targets[j], bench.get(), samples.get());
|
||||
|
||||
bench->perCanvasPostDraw(canvas);
|
||||
|
@ -63,7 +63,7 @@ struct Target {
|
||||
/** CPU-like targets can just be timed, but GPU-like
|
||||
targets need to pay attention to frame boundaries
|
||||
or other similar details. */
|
||||
virtual bool needsFrameTiming() const { return false; }
|
||||
virtual bool needsFrameTiming(int* frameLag) const { return false; }
|
||||
|
||||
/** Called once per target, during program initialization.
|
||||
Returns false if initialization fails. */
|
||||
|
@ -42,7 +42,9 @@ void HWUITarget::fence() {
|
||||
this->renderer.proxy->fence();
|
||||
}
|
||||
|
||||
bool HWUITarget::needsFrameTiming() const {
|
||||
bool HWUITarget::needsFrameTiming(int* frameLag) const {
|
||||
extern int FLAGS_gpuFrameLag;
|
||||
*frameLag = FLAGS_gpuFrameLag;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ struct HWUITarget : public Target {
|
||||
SkCanvas* beginTiming(SkCanvas* canvas) override;
|
||||
void endTiming() override;
|
||||
void fence() override;
|
||||
bool needsFrameTiming() const override;
|
||||
bool needsFrameTiming(int* frameLag) const override;
|
||||
|
||||
bool init(SkImageInfo info, Benchmark* bench) override;
|
||||
bool capturePixels(SkBitmap* bmp) override;
|
||||
|
@ -30,6 +30,8 @@
|
||||
* comments in GrGLConfig.h
|
||||
*/
|
||||
|
||||
typedef void(*GrGLFuncPtr)();
|
||||
|
||||
struct GrGLInterface;
|
||||
|
||||
const GrGLInterface* GrGLDefaultInterface();
|
||||
|
@ -9,6 +9,7 @@
|
||||
#define SkGLContext_DEFINED
|
||||
|
||||
#include "GrGLInterface.h"
|
||||
#include "../../src/gpu/SkGpuFenceSync.h"
|
||||
|
||||
/**
|
||||
* Create an offscreen opengl context with an RGBA8 / 8bit stencil FBO.
|
||||
@ -25,19 +26,32 @@ public:
|
||||
|
||||
const GrGLInterface* gl() const { return fGL.get(); }
|
||||
|
||||
virtual void makeCurrent() const = 0;
|
||||
bool fenceSyncSupport() const { return SkToBool(fFenceSync); }
|
||||
|
||||
bool getMaxGpuFrameLag(int* maxFrameLag) const {
|
||||
if (!fFenceSync) {
|
||||
return false;
|
||||
}
|
||||
*maxFrameLag = kMaxFrameLag;
|
||||
return true;
|
||||
}
|
||||
|
||||
void makeCurrent() const;
|
||||
|
||||
/**
|
||||
* The primary purpose of this function it to provide a means of scheduling
|
||||
* The only purpose of this function it to provide a means of scheduling
|
||||
* work on the GPU (since all of the subclasses create primary buffers for
|
||||
* testing that are small and not meant to be rendered to the screen).
|
||||
*
|
||||
* If the drawing surface provided by the platform is double buffered this
|
||||
* call will cause the platform to swap which buffer is currently being
|
||||
* targeted. If the current surface does not include a back buffer, this
|
||||
* call has no effect.
|
||||
* If the platform supports fence sync (OpenGL 3.2+ or EGL_KHR_fence_sync),
|
||||
* this will not swap any buffers, but rather emulate triple buffer
|
||||
* synchronization using fences.
|
||||
*
|
||||
* Otherwise it will call the platform SwapBuffers method. This may or may
|
||||
* not perform some sort of synchronization, depending on whether the
|
||||
* drawing surface provided by the platform is double buffered.
|
||||
*/
|
||||
virtual void swapBuffers() const = 0;
|
||||
void swapBuffers();
|
||||
|
||||
/**
|
||||
* This notifies the context that we are deliberately testing abandoning
|
||||
@ -47,13 +61,37 @@ public:
|
||||
*/
|
||||
void testAbandon();
|
||||
|
||||
class GLFenceSync; // SkGpuFenceSync implementation that uses the OpenGL functionality.
|
||||
|
||||
protected:
|
||||
SkGLContext();
|
||||
|
||||
/*
|
||||
* Methods that sublcasses must call from their constructors and destructors.
|
||||
*/
|
||||
void init(const GrGLInterface*, SkGpuFenceSync* = NULL);
|
||||
void teardown();
|
||||
|
||||
/*
|
||||
* Operations that have a platform-dependent implementation.
|
||||
*/
|
||||
virtual void onPlatformMakeCurrent() const = 0;
|
||||
virtual void onPlatformSwapBuffers() const = 0;
|
||||
virtual GrGLFuncPtr onPlatformGetProcAddress(const char*) const = 0;
|
||||
|
||||
private:
|
||||
enum { kMaxFrameLag = 3 };
|
||||
|
||||
SkAutoTDelete<SkGpuFenceSync> fFenceSync;
|
||||
SkPlatformGpuFence fFrameFences[kMaxFrameLag - 1];
|
||||
int fCurrentFenceIdx;
|
||||
|
||||
/** Subclass provides the gl interface object if construction was
|
||||
* successful. */
|
||||
SkAutoTUnref<const GrGLInterface> fGL;
|
||||
|
||||
friend class GLFenceSync; // For onPlatformGetProcAddress.
|
||||
|
||||
typedef SkRefCnt INHERITED;
|
||||
};
|
||||
|
||||
|
@ -13,8 +13,6 @@
|
||||
class SK_API SkNullGLContext : public SkGLContext {
|
||||
public:
|
||||
~SkNullGLContext() override;
|
||||
void makeCurrent() const override;
|
||||
void swapBuffers() const override {};
|
||||
|
||||
static SkNullGLContext* Create(GrGLStandard);
|
||||
|
||||
@ -23,6 +21,10 @@ public:
|
||||
private:
|
||||
SkNullGLContext();
|
||||
|
||||
void onPlatformMakeCurrent() const override;
|
||||
void onPlatformSwapBuffers() const override {}
|
||||
GrGLFuncPtr onPlatformGetProcAddress(const char*) const override { return NULL; }
|
||||
|
||||
ContextState* fState;
|
||||
};
|
||||
|
||||
|
@ -15,8 +15,6 @@
|
||||
class SkANGLEGLContext : public SkGLContext {
|
||||
public:
|
||||
~SkANGLEGLContext() override;
|
||||
void makeCurrent() const override;
|
||||
void swapBuffers() const override;
|
||||
|
||||
static SkANGLEGLContext* Create(GrGLStandard forcedGpuAPI) {
|
||||
if (kGL_GrGLStandard == forcedGpuAPI) {
|
||||
@ -37,6 +35,10 @@ private:
|
||||
SkANGLEGLContext();
|
||||
void destroyGLContext();
|
||||
|
||||
void onPlatformMakeCurrent() const override;
|
||||
void onPlatformSwapBuffers() const override;
|
||||
GrGLFuncPtr onPlatformGetProcAddress(const char* name) const override;
|
||||
|
||||
void* fContext;
|
||||
void* fDisplay;
|
||||
void* fSurface;
|
||||
|
29
src/gpu/SkGpuFenceSync.h
Normal file
29
src/gpu/SkGpuFenceSync.h
Normal file
@ -0,0 +1,29 @@
|
||||
|
||||
/*
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
#ifndef SkGpuFenceSync_DEFINED
|
||||
#define SkGpuFenceSync_DEFINED
|
||||
|
||||
#include "SkTypes.h"
|
||||
|
||||
typedef void* SkPlatformGpuFence;
|
||||
|
||||
/*
|
||||
* This class provides an interface to interact with fence syncs. A fence sync is an object that the
|
||||
* client can insert into the GPU command stream, and then at any future time, wait until all
|
||||
* commands that were issued before the fence have completed.
|
||||
*/
|
||||
class SkGpuFenceSync {
|
||||
public:
|
||||
virtual SkPlatformGpuFence SK_WARN_UNUSED_RESULT insertFence() const = 0;
|
||||
virtual bool flushAndWaitFence(SkPlatformGpuFence) const = 0;
|
||||
virtual void deleteFence(SkPlatformGpuFence) const = 0;
|
||||
|
||||
virtual ~SkGpuFenceSync() {}
|
||||
};
|
||||
|
||||
#endif
|
@ -8,7 +8,6 @@
|
||||
|
||||
#include "gl/GrGLInterface.h"
|
||||
|
||||
typedef void(*GrGLFuncPtr)();
|
||||
typedef GrGLFuncPtr (*GrGLGetProc)(void* ctx, const char name[]);
|
||||
|
||||
|
||||
|
@ -7,16 +7,148 @@
|
||||
*/
|
||||
#include "gl/SkGLContext.h"
|
||||
#include "GrGLUtil.h"
|
||||
#include "SkGpuFenceSync.h"
|
||||
|
||||
SkGLContext::SkGLContext() {
|
||||
class SkGLContext::GLFenceSync : public SkGpuFenceSync {
|
||||
public:
|
||||
static GLFenceSync* CreateIfSupported(const SkGLContext*);
|
||||
|
||||
SkPlatformGpuFence SK_WARN_UNUSED_RESULT insertFence() const override;
|
||||
bool flushAndWaitFence(SkPlatformGpuFence fence) const override;
|
||||
void deleteFence(SkPlatformGpuFence fence) const override;
|
||||
|
||||
private:
|
||||
GLFenceSync() {}
|
||||
|
||||
static const GrGLenum GL_SYNC_GPU_COMMANDS_COMPLETE = 0x9117;
|
||||
static const GrGLenum GL_WAIT_FAILED = 0x911d;
|
||||
static const GrGLbitfield GL_SYNC_FLUSH_COMMANDS_BIT = 0x00000001;
|
||||
|
||||
typedef struct __GLsync *GLsync;
|
||||
|
||||
typedef GLsync (GR_GL_FUNCTION_TYPE* GLFenceSyncProc) (GrGLenum, GrGLbitfield);
|
||||
typedef GrGLenum (GR_GL_FUNCTION_TYPE* GLClientWaitSyncProc) (GLsync, GrGLbitfield, GrGLuint64);
|
||||
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GLDeleteSyncProc) (GLsync);
|
||||
|
||||
GLFenceSyncProc fGLFenceSync;
|
||||
GLClientWaitSyncProc fGLClientWaitSync;
|
||||
GLDeleteSyncProc fGLDeleteSync;
|
||||
|
||||
typedef SkGpuFenceSync INHERITED;
|
||||
};
|
||||
|
||||
SkGLContext::SkGLContext()
|
||||
: fCurrentFenceIdx(0) {
|
||||
memset(fFrameFences, 0, sizeof(fFrameFences));
|
||||
}
|
||||
|
||||
SkGLContext::~SkGLContext() {
|
||||
SkASSERT(NULL == fGL.get()); // Subclass should destroy the interface.
|
||||
// Subclass should call teardown.
|
||||
#ifdef SK_DEBUG
|
||||
for (size_t i = 0; i < SK_ARRAY_COUNT(fFrameFences); i++) {
|
||||
SkASSERT(0 == fFrameFences[i]);
|
||||
}
|
||||
#endif
|
||||
SkASSERT(NULL == fGL.get());
|
||||
SkASSERT(NULL == fFenceSync.get());
|
||||
}
|
||||
|
||||
void SkGLContext::init(const GrGLInterface* gl, SkGpuFenceSync* fenceSync) {
|
||||
SkASSERT(!fGL.get());
|
||||
fGL.reset(gl);
|
||||
fFenceSync.reset(fenceSync ? fenceSync : GLFenceSync::CreateIfSupported(this));
|
||||
}
|
||||
|
||||
void SkGLContext::teardown() {
|
||||
if (fFenceSync) {
|
||||
for (size_t i = 0; i < SK_ARRAY_COUNT(fFrameFences); i++) {
|
||||
if (fFrameFences[i]) {
|
||||
fFenceSync->deleteFence(fFrameFences[i]);
|
||||
fFrameFences[i] = 0;
|
||||
}
|
||||
}
|
||||
fFenceSync.reset(NULL);
|
||||
}
|
||||
|
||||
fGL.reset(NULL);
|
||||
}
|
||||
|
||||
void SkGLContext::makeCurrent() const {
|
||||
this->onPlatformMakeCurrent();
|
||||
}
|
||||
|
||||
void SkGLContext::swapBuffers() {
|
||||
if (!fFenceSync) {
|
||||
// Fallback on the platform SwapBuffers method for synchronization. This may have no effect.
|
||||
this->onPlatformSwapBuffers();
|
||||
return;
|
||||
}
|
||||
|
||||
if (fFrameFences[fCurrentFenceIdx]) {
|
||||
if (!fFenceSync->flushAndWaitFence(fFrameFences[fCurrentFenceIdx])) {
|
||||
SkDebugf("WARNING: Wait failed for fence sync. Timings might not be accurate.\n");
|
||||
}
|
||||
fFenceSync->deleteFence(fFrameFences[fCurrentFenceIdx]);
|
||||
}
|
||||
|
||||
fFrameFences[fCurrentFenceIdx] = fFenceSync->insertFence();
|
||||
fCurrentFenceIdx = (fCurrentFenceIdx + 1) % SK_ARRAY_COUNT(fFrameFences);
|
||||
}
|
||||
|
||||
void SkGLContext::testAbandon() {
|
||||
if (fGL) {
|
||||
fGL->abandon();
|
||||
}
|
||||
if (fFenceSync) {
|
||||
memset(fFrameFences, 0, sizeof(fFrameFences));
|
||||
}
|
||||
}
|
||||
|
||||
SkGLContext::GLFenceSync* SkGLContext::GLFenceSync::CreateIfSupported(const SkGLContext* ctx) {
|
||||
SkAutoTDelete<GLFenceSync> ret(SkNEW(GLFenceSync));
|
||||
|
||||
if (kGL_GrGLStandard == ctx->gl()->fStandard) {
|
||||
const GrGLubyte* versionStr;
|
||||
SK_GL_RET(*ctx, versionStr, GetString(GR_GL_VERSION));
|
||||
GrGLVersion version = GrGLGetVersionFromString(reinterpret_cast<const char*>(versionStr));
|
||||
if (version < GR_GL_VER(3,2) && !ctx->gl()->hasExtension("GL_ARB_sync")) {
|
||||
return NULL;
|
||||
}
|
||||
ret->fGLFenceSync = reinterpret_cast<GLFenceSyncProc>(
|
||||
ctx->onPlatformGetProcAddress("glFenceSync"));
|
||||
ret->fGLClientWaitSync = reinterpret_cast<GLClientWaitSyncProc>(
|
||||
ctx->onPlatformGetProcAddress("glClientWaitSync"));
|
||||
ret->fGLDeleteSync = reinterpret_cast<GLDeleteSyncProc>(
|
||||
ctx->onPlatformGetProcAddress("glDeleteSync"));
|
||||
} else {
|
||||
if (!ctx->gl()->hasExtension("GL_APPLE_sync")) {
|
||||
return NULL;
|
||||
}
|
||||
ret->fGLFenceSync = reinterpret_cast<GLFenceSyncProc>(
|
||||
ctx->onPlatformGetProcAddress("glFenceSyncAPPLE"));
|
||||
ret->fGLClientWaitSync = reinterpret_cast<GLClientWaitSyncProc>(
|
||||
ctx->onPlatformGetProcAddress("glClientWaitSyncAPPLE"));
|
||||
ret->fGLDeleteSync = reinterpret_cast<GLDeleteSyncProc>(
|
||||
ctx->onPlatformGetProcAddress("glDeleteSyncAPPLE"));
|
||||
}
|
||||
|
||||
if (!ret->fGLFenceSync || !ret->fGLClientWaitSync || !ret->fGLDeleteSync) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret.detach();
|
||||
}
|
||||
|
||||
SkPlatformGpuFence SkGLContext::GLFenceSync::insertFence() const {
|
||||
return fGLFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
}
|
||||
|
||||
bool SkGLContext::GLFenceSync::flushAndWaitFence(SkPlatformGpuFence fence) const {
|
||||
GLsync glsync = static_cast<GLsync>(fence);
|
||||
return GL_WAIT_FAILED != fGLClientWaitSync(glsync, GL_SYNC_FLUSH_COMMANDS_BIT, -1);
|
||||
}
|
||||
|
||||
void SkGLContext::GLFenceSync::deleteFence(SkPlatformGpuFence fence) const {
|
||||
GLsync glsync = static_cast<GLsync>(fence);
|
||||
fGLDeleteSync(glsync);
|
||||
}
|
||||
|
@ -547,7 +547,7 @@ SkNullGLContext* SkNullGLContext::Create(GrGLStandard forcedGpuAPI) {
|
||||
SkNullGLContext::SkNullGLContext() {
|
||||
fState = SkNEW(ContextState);
|
||||
GrGLInterface* interface = create_null_interface(fState);
|
||||
fGL.reset(interface);
|
||||
this->init(interface);
|
||||
#if GR_GL_PER_GL_FUNC_CALLBACK
|
||||
interface->fCallback = set_current_context_from_interface;
|
||||
interface->fCallbackData = reinterpret_cast<GrGLInterfaceCallbackData>(fState);
|
||||
@ -555,8 +555,8 @@ SkNullGLContext::SkNullGLContext() {
|
||||
}
|
||||
|
||||
SkNullGLContext::~SkNullGLContext() {
|
||||
fGL.reset(NULL);
|
||||
this->teardown();
|
||||
fState->unref();
|
||||
}
|
||||
|
||||
void SkNullGLContext::makeCurrent() const { set_current_context(fState); }
|
||||
void SkNullGLContext::onPlatformMakeCurrent() const { set_current_context(fState); }
|
||||
|
@ -96,25 +96,27 @@ SkANGLEGLContext::SkANGLEGLContext()
|
||||
|
||||
eglMakeCurrent(fDisplay, fSurface, fSurface, fContext);
|
||||
|
||||
fGL.reset(GrGLCreateANGLEInterface());
|
||||
if (NULL == fGL.get()) {
|
||||
SkAutoTUnref<const GrGLInterface> gl(GrGLCreateANGLEInterface());
|
||||
if (NULL == gl.get()) {
|
||||
SkDebugf("Could not create ANGLE GL interface!\n");
|
||||
this->destroyGLContext();
|
||||
return;
|
||||
}
|
||||
if (!fGL->validate()) {
|
||||
if (!gl->validate()) {
|
||||
SkDebugf("Could not validate ANGLE GL interface!\n");
|
||||
this->destroyGLContext();
|
||||
return;
|
||||
}
|
||||
|
||||
this->init(gl.detach());
|
||||
}
|
||||
|
||||
SkANGLEGLContext::~SkANGLEGLContext() {
|
||||
this->teardown();
|
||||
this->destroyGLContext();
|
||||
}
|
||||
|
||||
void SkANGLEGLContext::destroyGLContext() {
|
||||
fGL.reset(NULL);
|
||||
if (fDisplay) {
|
||||
eglMakeCurrent(fDisplay, 0, 0, 0);
|
||||
|
||||
@ -133,14 +135,18 @@ void SkANGLEGLContext::destroyGLContext() {
|
||||
}
|
||||
}
|
||||
|
||||
void SkANGLEGLContext::makeCurrent() const {
|
||||
void SkANGLEGLContext::onPlatformMakeCurrent() const {
|
||||
if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
|
||||
SkDebugf("Could not set the context.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void SkANGLEGLContext::swapBuffers() const {
|
||||
void SkANGLEGLContext::onPlatformSwapBuffers() const {
|
||||
if (!eglSwapBuffers(fDisplay, fSurface)) {
|
||||
SkDebugf("Could not complete eglSwapBuffers.\n");
|
||||
}
|
||||
}
|
||||
|
||||
GrGLFuncPtr SkANGLEGLContext::onPlatformGetProcAddress(const char* name) const {
|
||||
return eglGetProcAddress(name);
|
||||
}
|
||||
|
@ -9,9 +9,9 @@
|
||||
#include "gl/debug/SkDebugGLContext.h"
|
||||
|
||||
SkDebugGLContext::SkDebugGLContext() {
|
||||
fGL.reset(GrGLCreateDebugInterface());
|
||||
this->init(GrGLCreateDebugInterface());
|
||||
}
|
||||
|
||||
SkDebugGLContext::~SkDebugGLContext() {
|
||||
fGL.reset(NULL);
|
||||
this->teardown();
|
||||
}
|
||||
|
@ -13,8 +13,6 @@
|
||||
class SkDebugGLContext : public SkGLContext {
|
||||
public:
|
||||
~SkDebugGLContext() override;
|
||||
void makeCurrent() const override {}
|
||||
void swapBuffers() const override {}
|
||||
|
||||
static SkDebugGLContext* Create(GrGLStandard forcedGpuAPI) {
|
||||
if (kGLES_GrGLStandard == forcedGpuAPI) {
|
||||
@ -23,6 +21,10 @@ public:
|
||||
return SkNEW(SkDebugGLContext);
|
||||
}
|
||||
private:
|
||||
void onPlatformMakeCurrent() const override {}
|
||||
void onPlatformSwapBuffers() const override {}
|
||||
GrGLFuncPtr onPlatformGetProcAddress(const char*) const override { return NULL; }
|
||||
|
||||
SkDebugGLContext();
|
||||
};
|
||||
|
||||
|
@ -8,20 +8,42 @@
|
||||
#include "gl/SkGLContext.h"
|
||||
|
||||
#include <GLES2/gl2.h>
|
||||
|
||||
#define EGL_EGLEXT_PROTOTYPES
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
|
||||
namespace {
|
||||
|
||||
// TODO: Share this class with ANGLE if/when it gets support for EGL_KHR_fence_sync.
|
||||
class SkEGLFenceSync : public SkGpuFenceSync {
|
||||
public:
|
||||
static SkEGLFenceSync* CreateIfSupported(EGLDisplay);
|
||||
|
||||
SkPlatformGpuFence SK_WARN_UNUSED_RESULT insertFence() const override;
|
||||
bool flushAndWaitFence(SkPlatformGpuFence fence) const override;
|
||||
void deleteFence(SkPlatformGpuFence fence) const override;
|
||||
|
||||
private:
|
||||
SkEGLFenceSync(EGLDisplay display) : fDisplay(display) {}
|
||||
|
||||
EGLDisplay fDisplay;
|
||||
|
||||
typedef SkGpuFenceSync INHERITED;
|
||||
};
|
||||
|
||||
class EGLGLContext : public SkGLContext {
|
||||
public:
|
||||
EGLGLContext(GrGLStandard forcedGpuAPI);
|
||||
~EGLGLContext() override;
|
||||
void makeCurrent() const override;
|
||||
void swapBuffers() const override;
|
||||
|
||||
private:
|
||||
void destroyGLContext();
|
||||
|
||||
void onPlatformMakeCurrent() const override;
|
||||
void onPlatformSwapBuffers() const override;
|
||||
GrGLFuncPtr onPlatformGetProcAddress(const char*) const override;
|
||||
|
||||
EGLContext fContext;
|
||||
EGLDisplay fDisplay;
|
||||
EGLSurface fSurface;
|
||||
@ -69,7 +91,9 @@ EGLGLContext::EGLGLContext(GrGLStandard forcedGpuAPI)
|
||||
}
|
||||
SkASSERT(forcedGpuAPI == kNone_GrGLStandard || kAPIs[api].fStandard == forcedGpuAPI);
|
||||
|
||||
for (; NULL == fGL.get() && api < apiLimit; ++api) {
|
||||
SkAutoTUnref<const GrGLInterface> gl;
|
||||
|
||||
for (; NULL == gl.get() && api < apiLimit; ++api) {
|
||||
fDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
|
||||
EGLint majorVersion;
|
||||
@ -134,27 +158,30 @@ EGLGLContext::EGLGLContext(GrGLStandard forcedGpuAPI)
|
||||
continue;
|
||||
}
|
||||
|
||||
fGL.reset(GrGLCreateNativeInterface());
|
||||
if (NULL == fGL.get()) {
|
||||
gl.reset(GrGLCreateNativeInterface());
|
||||
if (NULL == gl.get()) {
|
||||
SkDebugf("Failed to create gl interface.\n");
|
||||
this->destroyGLContext();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!fGL->validate()) {
|
||||
if (!gl->validate()) {
|
||||
SkDebugf("Failed to validate gl interface.\n");
|
||||
this->destroyGLContext();
|
||||
continue;
|
||||
}
|
||||
|
||||
this->init(gl.detach(), SkEGLFenceSync::CreateIfSupported(fDisplay));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
EGLGLContext::~EGLGLContext() {
|
||||
this->teardown();
|
||||
this->destroyGLContext();
|
||||
}
|
||||
|
||||
void EGLGLContext::destroyGLContext() {
|
||||
fGL.reset(NULL);
|
||||
if (fDisplay) {
|
||||
eglMakeCurrent(fDisplay, 0, 0, 0);
|
||||
|
||||
@ -174,18 +201,61 @@ void EGLGLContext::destroyGLContext() {
|
||||
}
|
||||
|
||||
|
||||
void EGLGLContext::makeCurrent() const {
|
||||
void EGLGLContext::onPlatformMakeCurrent() const {
|
||||
if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
|
||||
SkDebugf("Could not set the context.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void EGLGLContext::swapBuffers() const {
|
||||
void EGLGLContext::onPlatformSwapBuffers() const {
|
||||
if (!eglSwapBuffers(fDisplay, fSurface)) {
|
||||
SkDebugf("Could not complete eglSwapBuffers.\n");
|
||||
}
|
||||
}
|
||||
|
||||
GrGLFuncPtr EGLGLContext::onPlatformGetProcAddress(const char* procName) const {
|
||||
return eglGetProcAddress(procName);
|
||||
}
|
||||
|
||||
static bool supports_egl_extension(EGLDisplay display, const char* extension) {
|
||||
int extensionLength = strlen(extension);
|
||||
const char* extensionsStr = eglQueryString(display, EGL_EXTENSIONS);
|
||||
while (const char* match = strstr(extensionsStr, extension)) {
|
||||
// Ensure the string we found is its own extension, not a substring of a larger extension
|
||||
// (e.g. GL_ARB_occlusion_query / GL_ARB_occlusion_query2).
|
||||
if ((match == extensionsStr || match[-1] == ' ') &&
|
||||
(match[extensionLength] == ' ' || match[extensionLength] == '\0')) {
|
||||
return true;
|
||||
}
|
||||
extensionsStr = match + extensionLength;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SkEGLFenceSync* SkEGLFenceSync::CreateIfSupported(EGLDisplay display) {
|
||||
if (!display || !supports_egl_extension(display, "EGL_KHR_fence_sync")) {
|
||||
return NULL;
|
||||
}
|
||||
return SkNEW_ARGS(SkEGLFenceSync, (display));
|
||||
}
|
||||
|
||||
SkPlatformGpuFence SkEGLFenceSync::insertFence() const {
|
||||
return eglCreateSyncKHR(fDisplay, EGL_SYNC_FENCE_KHR, NULL);
|
||||
}
|
||||
|
||||
bool SkEGLFenceSync::flushAndWaitFence(SkPlatformGpuFence platformFence) const {
|
||||
EGLSyncKHR eglsync = static_cast<EGLSyncKHR>(platformFence);
|
||||
return EGL_CONDITION_SATISFIED_KHR == eglClientWaitSyncKHR(fDisplay,
|
||||
eglsync,
|
||||
EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
|
||||
EGL_FOREVER_KHR);
|
||||
}
|
||||
|
||||
void SkEGLFenceSync::deleteFence(SkPlatformGpuFence platformFence) const {
|
||||
EGLSyncKHR eglsync = static_cast<EGLSyncKHR>(platformFence);
|
||||
eglDestroySyncKHR(fDisplay, eglsync);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
SkGLContext* SkCreatePlatformGLContext(GrGLStandard forcedGpuAPI) {
|
||||
|
@ -48,12 +48,14 @@ class GLXGLContext : public SkGLContext {
|
||||
public:
|
||||
GLXGLContext(GrGLStandard forcedGpuAPI);
|
||||
~GLXGLContext() override;
|
||||
void makeCurrent() const override;
|
||||
void swapBuffers() const override;
|
||||
|
||||
private:
|
||||
void destroyGLContext();
|
||||
|
||||
void onPlatformMakeCurrent() const override;
|
||||
void onPlatformSwapBuffers() const override;
|
||||
GrGLFuncPtr onPlatformGetProcAddress(const char*) const override;
|
||||
|
||||
GLXContext fContext;
|
||||
Display* fDisplay;
|
||||
Pixmap fPixmap;
|
||||
@ -267,27 +269,29 @@ GLXGLContext::GLXGLContext(GrGLStandard forcedGpuAPI)
|
||||
return;
|
||||
}
|
||||
|
||||
fGL.reset(GrGLCreateNativeInterface());
|
||||
if (NULL == fGL.get()) {
|
||||
SkAutoTUnref<const GrGLInterface> gl(GrGLCreateNativeInterface());
|
||||
if (NULL == gl.get()) {
|
||||
SkDebugf("Failed to create gl interface");
|
||||
this->destroyGLContext();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fGL->validate()) {
|
||||
if (!gl->validate()) {
|
||||
SkDebugf("Failed to validate gl interface");
|
||||
this->destroyGLContext();
|
||||
return;
|
||||
}
|
||||
|
||||
this->init(gl.detach());
|
||||
}
|
||||
|
||||
|
||||
GLXGLContext::~GLXGLContext() {
|
||||
this->teardown();
|
||||
this->destroyGLContext();
|
||||
}
|
||||
|
||||
void GLXGLContext::destroyGLContext() {
|
||||
fGL.reset(NULL);
|
||||
if (fDisplay) {
|
||||
glXMakeCurrent(fDisplay, 0, 0);
|
||||
|
||||
@ -311,16 +315,20 @@ void GLXGLContext::destroyGLContext() {
|
||||
}
|
||||
}
|
||||
|
||||
void GLXGLContext::makeCurrent() const {
|
||||
void GLXGLContext::onPlatformMakeCurrent() const {
|
||||
if (!glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) {
|
||||
SkDebugf("Could not set the context.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void GLXGLContext::swapBuffers() const {
|
||||
void GLXGLContext::onPlatformSwapBuffers() const {
|
||||
glXSwapBuffers(fDisplay, fGlxPixmap);
|
||||
}
|
||||
|
||||
GrGLFuncPtr GLXGLContext::onPlatformGetProcAddress(const char* procName) const {
|
||||
return glXGetProcAddress(reinterpret_cast<const GLubyte*>(procName));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
SkGLContext* SkCreatePlatformGLContext(GrGLStandard forcedGpuAPI) {
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "gl/SkGLContext.h"
|
||||
#import <OpenGLES/EAGL.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#define EAGLCTX ((EAGLContext*)(fEAGLContext))
|
||||
|
||||
@ -17,40 +18,50 @@ class IOSGLContext : public SkGLContext {
|
||||
public:
|
||||
IOSGLContext();
|
||||
~IOSGLContext() override;
|
||||
void makeCurrent() const override;
|
||||
void swapBuffers() const override;
|
||||
|
||||
private:
|
||||
void destroyGLContext();
|
||||
|
||||
void onPlatformMakeCurrent() const override;
|
||||
void onPlatformSwapBuffers() const override;
|
||||
GrGLFuncPtr onPlatformGetProcAddress(const char*) const override;
|
||||
|
||||
void* fEAGLContext;
|
||||
void* fGLLibrary;
|
||||
};
|
||||
|
||||
IOSGLContext::IOSGLContext()
|
||||
: fEAGLContext(NULL) {
|
||||
: fEAGLContext(NULL)
|
||||
, fGLLibrary(RTLD_DEFAULT) {
|
||||
|
||||
fEAGLContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
|
||||
[EAGLContext setCurrentContext:EAGLCTX];
|
||||
|
||||
fGL.reset(GrGLCreateNativeInterface());
|
||||
if (NULL == fGL.get()) {
|
||||
SkAutoTUnref<const GrGLInterface> gl(GrGLCreateNativeInterface());
|
||||
if (NULL == gl.get()) {
|
||||
SkDebugf("Failed to create gl interface");
|
||||
this->destroyGLContext();
|
||||
return;
|
||||
}
|
||||
if (!fGL->validate()) {
|
||||
if (!gl->validate()) {
|
||||
SkDebugf("Failed to validate gl interface");
|
||||
this->destroyGLContext();
|
||||
return;
|
||||
}
|
||||
|
||||
fGLLibrary = dlopen(
|
||||
"/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib",
|
||||
RTLD_LAZY);
|
||||
|
||||
this->init(gl.detach());
|
||||
}
|
||||
|
||||
IOSGLContext::~IOSGLContext() {
|
||||
this->teardown();
|
||||
this->destroyGLContext();
|
||||
}
|
||||
|
||||
void IOSGLContext::destroyGLContext() {
|
||||
fGL.reset(NULL);
|
||||
if (fEAGLContext) {
|
||||
if ([EAGLContext currentContext] == EAGLCTX) {
|
||||
[EAGLContext setCurrentContext:nil];
|
||||
@ -58,16 +69,23 @@ void IOSGLContext::destroyGLContext() {
|
||||
[EAGLCTX release];
|
||||
fEAGLContext = NULL;
|
||||
}
|
||||
if (RTLD_DEFAULT != fGLLibrary) {
|
||||
dlclose(fGLLibrary);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void IOSGLContext::makeCurrent() const {
|
||||
void IOSGLContext::onPlatformMakeCurrent() const {
|
||||
if (![EAGLContext setCurrentContext:EAGLCTX]) {
|
||||
SkDebugf("Could not set the context.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void IOSGLContext::swapBuffers() const { }
|
||||
void IOSGLContext::onPlatformSwapBuffers() const { }
|
||||
|
||||
GrGLFuncPtr IOSGLContext::onPlatformGetProcAddress(const char* procName) const {
|
||||
return reinterpret_cast<GrGLFuncPtr>(dlsym(fGLLibrary, procName));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
@ -9,23 +9,28 @@
|
||||
#include "AvailabilityMacros.h"
|
||||
|
||||
#include <OpenGL/OpenGL.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
namespace {
|
||||
class MacGLContext : public SkGLContext {
|
||||
public:
|
||||
MacGLContext();
|
||||
~MacGLContext() override;
|
||||
void makeCurrent() const override;
|
||||
void swapBuffers() const override;
|
||||
|
||||
private:
|
||||
void destroyGLContext();
|
||||
|
||||
void onPlatformMakeCurrent() const override;
|
||||
void onPlatformSwapBuffers() const override;
|
||||
GrGLFuncPtr onPlatformGetProcAddress(const char*) const override;
|
||||
|
||||
CGLContextObj fContext;
|
||||
void* fGLLibrary;
|
||||
};
|
||||
|
||||
MacGLContext::MacGLContext()
|
||||
: fContext(NULL) {
|
||||
: fContext(NULL)
|
||||
, fGLLibrary(RTLD_DEFAULT) {
|
||||
CGLPixelFormatAttribute attributes[] = {
|
||||
#if MAC_OS_X_VERSION_10_7
|
||||
kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute) kCGLOGLPVersion_3_2_Core,
|
||||
@ -53,39 +58,52 @@ MacGLContext::MacGLContext()
|
||||
|
||||
CGLSetCurrentContext(fContext);
|
||||
|
||||
fGL.reset(GrGLCreateNativeInterface());
|
||||
if (NULL == fGL.get()) {
|
||||
SkAutoTUnref<const GrGLInterface> gl(GrGLCreateNativeInterface());
|
||||
if (NULL == gl.get()) {
|
||||
SkDebugf("Context could not create GL interface.\n");
|
||||
this->destroyGLContext();
|
||||
return;
|
||||
}
|
||||
if (!fGL->validate()) {
|
||||
if (!gl->validate()) {
|
||||
SkDebugf("Context could not validate GL interface.\n");
|
||||
this->destroyGLContext();
|
||||
return;
|
||||
}
|
||||
|
||||
fGLLibrary = dlopen(
|
||||
"/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib",
|
||||
RTLD_LAZY);
|
||||
|
||||
this->init(gl.detach());
|
||||
}
|
||||
|
||||
MacGLContext::~MacGLContext() {
|
||||
this->teardown();
|
||||
this->destroyGLContext();
|
||||
}
|
||||
|
||||
void MacGLContext::destroyGLContext() {
|
||||
fGL.reset(NULL);
|
||||
if (fContext) {
|
||||
CGLReleaseContext(fContext);
|
||||
fContext = NULL;
|
||||
}
|
||||
if (RTLD_DEFAULT != fGLLibrary) {
|
||||
dlclose(fGLLibrary);
|
||||
}
|
||||
}
|
||||
|
||||
void MacGLContext::makeCurrent() const {
|
||||
void MacGLContext::onPlatformMakeCurrent() const {
|
||||
CGLSetCurrentContext(fContext);
|
||||
}
|
||||
|
||||
void MacGLContext::swapBuffers() const {
|
||||
void MacGLContext::onPlatformSwapBuffers() const {
|
||||
CGLFlushDrawable(fContext);
|
||||
}
|
||||
|
||||
GrGLFuncPtr MacGLContext::onPlatformGetProcAddress(const char* procName) const {
|
||||
return reinterpret_cast<GrGLFuncPtr>(dlsym(fGLLibrary, procName));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
SkGLContext* SkCreatePlatformGLContext(GrGLStandard forcedGpuAPI) {
|
||||
|
@ -50,26 +50,28 @@ SkMesaGLContext::SkMesaGLContext()
|
||||
return;
|
||||
}
|
||||
|
||||
fGL.reset(GrGLCreateMesaInterface());
|
||||
if (NULL == fGL.get()) {
|
||||
SkAutoTUnref<const GrGLInterface> gl(GrGLCreateMesaInterface());
|
||||
if (NULL == gl.get()) {
|
||||
SkDebugf("Could not create GL interface!\n");
|
||||
this->destroyGLContext();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fGL->validate()) {
|
||||
if (!gl->validate()) {
|
||||
SkDebugf("Could not validate GL interface!\n");
|
||||
this->destroyGLContext();
|
||||
return;
|
||||
}
|
||||
|
||||
this->init(gl.detach());
|
||||
}
|
||||
|
||||
SkMesaGLContext::~SkMesaGLContext() {
|
||||
this->teardown();
|
||||
this->destroyGLContext();
|
||||
}
|
||||
|
||||
void SkMesaGLContext::destroyGLContext() {
|
||||
fGL.reset(NULL);
|
||||
if (fImage) {
|
||||
sk_free(fImage);
|
||||
fImage = NULL;
|
||||
@ -83,7 +85,7 @@ void SkMesaGLContext::destroyGLContext() {
|
||||
|
||||
|
||||
|
||||
void SkMesaGLContext::makeCurrent() const {
|
||||
void SkMesaGLContext::onPlatformMakeCurrent() const {
|
||||
if (fContext) {
|
||||
if (!OSMesaMakeCurrent((OSMesaContext)fContext, fImage,
|
||||
GR_GL_UNSIGNED_BYTE, gBOGUS_SIZE, gBOGUS_SIZE)) {
|
||||
@ -92,4 +94,8 @@ void SkMesaGLContext::makeCurrent() const {
|
||||
}
|
||||
}
|
||||
|
||||
void SkMesaGLContext::swapBuffers() const { }
|
||||
void SkMesaGLContext::onPlatformSwapBuffers() const { }
|
||||
|
||||
GrGLFuncPtr SkMesaGLContext::onPlatformGetProcAddress(const char* procName) const {
|
||||
return OSMesaGetProcAddress(procName);
|
||||
}
|
||||
|
@ -18,8 +18,6 @@ private:
|
||||
|
||||
public:
|
||||
~SkMesaGLContext() override;
|
||||
void makeCurrent() const override;
|
||||
void swapBuffers() const override;
|
||||
|
||||
static SkMesaGLContext* Create(GrGLStandard forcedGpuAPI) {
|
||||
if (kGLES_GrGLStandard == forcedGpuAPI) {
|
||||
@ -37,6 +35,10 @@ private:
|
||||
SkMesaGLContext();
|
||||
void destroyGLContext();
|
||||
|
||||
void onPlatformMakeCurrent() const override;
|
||||
void onPlatformSwapBuffers() const override;
|
||||
GrGLFuncPtr onPlatformGetProcAddress(const char*) const override;
|
||||
|
||||
Context fContext;
|
||||
GrGLubyte *fImage;
|
||||
};
|
||||
|
@ -21,12 +21,14 @@ class WinGLContext : public SkGLContext {
|
||||
public:
|
||||
WinGLContext(GrGLStandard forcedGpuAPI);
|
||||
~WinGLContext() override;
|
||||
void makeCurrent() const override;
|
||||
void swapBuffers() const override;
|
||||
|
||||
private:
|
||||
void destroyGLContext();
|
||||
|
||||
void onPlatformMakeCurrent() const override;
|
||||
void onPlatformSwapBuffers() const override;
|
||||
GrGLFuncPtr onPlatformGetProcAddress(const char* name) const override;
|
||||
|
||||
HWND fWindow;
|
||||
HDC fDeviceContext;
|
||||
HGLRC fGlRenderContext;
|
||||
@ -113,25 +115,27 @@ WinGLContext::WinGLContext(GrGLStandard forcedGpuAPI)
|
||||
return;
|
||||
}
|
||||
|
||||
fGL.reset(GrGLCreateNativeInterface());
|
||||
if (NULL == fGL.get()) {
|
||||
SkAutoTUnref<const GrGLInterface> gl(GrGLCreateNativeInterface());
|
||||
if (NULL == gl.get()) {
|
||||
SkDebugf("Could not create GL interface.\n");
|
||||
this->destroyGLContext();
|
||||
return;
|
||||
}
|
||||
if (!fGL->validate()) {
|
||||
if (!gl->validate()) {
|
||||
SkDebugf("Could not validate GL interface.\n");
|
||||
this->destroyGLContext();
|
||||
return;
|
||||
}
|
||||
|
||||
this->init(gl.detach());
|
||||
}
|
||||
|
||||
WinGLContext::~WinGLContext() {
|
||||
this->teardown();
|
||||
this->destroyGLContext();
|
||||
}
|
||||
|
||||
void WinGLContext::destroyGLContext() {
|
||||
fGL.reset(NULL);
|
||||
SkSafeSetNull(fPbufferContext);
|
||||
if (fGlRenderContext) {
|
||||
wglDeleteContext(fGlRenderContext);
|
||||
@ -147,7 +151,7 @@ void WinGLContext::destroyGLContext() {
|
||||
}
|
||||
}
|
||||
|
||||
void WinGLContext::makeCurrent() const {
|
||||
void WinGLContext::onPlatformMakeCurrent() const {
|
||||
HDC dc;
|
||||
HGLRC glrc;
|
||||
|
||||
@ -164,7 +168,7 @@ void WinGLContext::makeCurrent() const {
|
||||
}
|
||||
}
|
||||
|
||||
void WinGLContext::swapBuffers() const {
|
||||
void WinGLContext::onPlatformSwapBuffers() const {
|
||||
HDC dc;
|
||||
|
||||
if (NULL == fPbufferContext) {
|
||||
@ -177,6 +181,10 @@ void WinGLContext::swapBuffers() const {
|
||||
}
|
||||
}
|
||||
|
||||
GrGLFuncPtr WinGLContext::onPlatformGetProcAddress(const char* name) const {
|
||||
return reinterpret_cast<GrGLFuncPtr>(wglGetProcAddress(name));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
SkGLContext* SkCreatePlatformGLContext(GrGLStandard forcedGpuAPI) {
|
||||
|
Loading…
Reference in New Issue
Block a user