| /* | |
| * Copyright 2011 Google Inc. | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "src/gpu/ganesh/gl/GrGLAttachment.h" | |
| #include "include/core/SkString.h" | |
| #include "include/core/SkTraceMemoryDump.h" | |
| #include "include/gpu/ganesh/gl/GrGLBackendSurface.h" | |
| #include "include/gpu/ganesh/gl/GrGLFunctions.h" | |
| #include "include/gpu/ganesh/gl/GrGLInterface.h" | |
| #include "src/gpu/ganesh/gl/GrGLCaps.h" | |
| #include "src/gpu/ganesh/gl/GrGLDefines.h" | |
| #include "src/gpu/ganesh/gl/GrGLGpu.h" | |
| #include "src/gpu/ganesh/gl/GrGLUtil.h" | |
| #include <string> | |
| #define GL_CALL(X) GR_GL_CALL(gpu->glInterface(), X) | |
| #define GL_ALLOC_CALL(call) \ | |
| [&] { \ | |
| if (gpu->glCaps().skipErrorChecks()) { \ | |
| GR_GL_CALL(gpu->glInterface(), call); \ | |
| return static_cast<GrGLenum>(GR_GL_NO_ERROR); \ | |
| } else { \ | |
| gpu->clearErrorsAndCheckForOOM(); \ | |
| GR_GL_CALL_NOERRCHECK(gpu->glInterface(), call); \ | |
| return gpu->getErrorAndCheckForOOM(); \ | |
| } \ | |
| }() | |
| static bool renderbuffer_storage_msaa(GrGLGpu* gpu, | |
| int sampleCount, | |
| GrGLenum format, | |
| int width, | |
| int height) { | |
| SkASSERT(GrGLCaps::kNone_MSFBOType != gpu->glCaps().msFBOType()); | |
| GrGLenum error; | |
| switch (gpu->glCaps().msFBOType()) { | |
| case GrGLCaps::kStandard_MSFBOType: | |
| error = GL_ALLOC_CALL(RenderbufferStorageMultisample( | |
| GR_GL_RENDERBUFFER, sampleCount, format, width, height)); | |
| break; | |
| case GrGLCaps::kES_Apple_MSFBOType: | |
| error = GL_ALLOC_CALL(RenderbufferStorageMultisampleES2APPLE( | |
| GR_GL_RENDERBUFFER, sampleCount, format, width, height)); | |
| break; | |
| case GrGLCaps::kES_EXT_MsToTexture_MSFBOType: | |
| case GrGLCaps::kES_IMG_MsToTexture_MSFBOType: | |
| error = GL_ALLOC_CALL(RenderbufferStorageMultisampleES2EXT( | |
| GR_GL_RENDERBUFFER, sampleCount, format, width, height)); | |
| break; | |
| case GrGLCaps::kNone_MSFBOType: | |
| SkUNREACHABLE; | |
| } | |
| return error == GR_GL_NO_ERROR; | |
| } | |
| sk_sp<GrGLAttachment> GrGLAttachment::MakeStencil(GrGLGpu* gpu, | |
| SkISize dimensions, | |
| int sampleCnt, | |
| GrGLFormat format) { | |
| GrGLuint rbID = 0; | |
| GL_CALL(GenRenderbuffers(1, &rbID)); | |
| if (!rbID) { | |
| return nullptr; | |
| } | |
| GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, rbID)); | |
| GrGLenum glFmt = GrGLFormatToEnum(format); | |
| // we do this "if" so that we don't call the multisample | |
| // version on a GL that doesn't have an MSAA extension. | |
| if (sampleCnt > 1) { | |
| if (!renderbuffer_storage_msaa(gpu, sampleCnt, glFmt, dimensions.width(), | |
| dimensions.height())) { | |
| GL_CALL(DeleteRenderbuffers(1, &rbID)); | |
| return nullptr; | |
| } | |
| } else { | |
| GrGLenum error = GL_ALLOC_CALL(RenderbufferStorage( | |
| GR_GL_RENDERBUFFER, glFmt, dimensions.width(), dimensions.height())); | |
| if (error != GR_GL_NO_ERROR) { | |
| GL_CALL(DeleteRenderbuffers(1, &rbID)); | |
| return nullptr; | |
| } | |
| } | |
| return sk_sp<GrGLAttachment>(new GrGLAttachment(gpu, | |
| rbID, | |
| dimensions, | |
| GrAttachment::UsageFlags::kStencilAttachment, | |
| sampleCnt, | |
| format, | |
| /*label=*/"GLAttachmentMakeStencil")); | |
| } | |
| sk_sp<GrGLAttachment> GrGLAttachment::MakeMSAA(GrGLGpu* gpu, | |
| SkISize dimensions, | |
| int sampleCnt, | |
| GrGLFormat format) { | |
| GrGLuint rbID = 0; | |
| GL_CALL(GenRenderbuffers(1, &rbID)); | |
| if (!rbID) { | |
| return nullptr; | |
| } | |
| GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, rbID)); | |
| GrGLenum glFmt = gpu->glCaps().getRenderbufferInternalFormat(format); | |
| if (!renderbuffer_storage_msaa( | |
| gpu, sampleCnt, glFmt, dimensions.width(), dimensions.height())) { | |
| GL_CALL(DeleteRenderbuffers(1, &rbID)); | |
| return nullptr; | |
| } | |
| return sk_sp<GrGLAttachment>(new GrGLAttachment(gpu, | |
| rbID, | |
| dimensions, | |
| GrAttachment::UsageFlags::kColorAttachment, | |
| sampleCnt, | |
| format, | |
| /*label=*/"GLAttachmentMakeMSAA")); | |
| } | |
| void GrGLAttachment::onRelease() { | |
| if (0 != fRenderbufferID) { | |
| GrGLGpu* gpuGL = (GrGLGpu*)this->getGpu(); | |
| const GrGLInterface* gl = gpuGL->glInterface(); | |
| GR_GL_CALL(gl, DeleteRenderbuffers(1, &fRenderbufferID)); | |
| fRenderbufferID = 0; | |
| } | |
| INHERITED::onRelease(); | |
| } | |
| void GrGLAttachment::onAbandon() { | |
| fRenderbufferID = 0; | |
| INHERITED::onAbandon(); | |
| } | |
| GrBackendFormat GrGLAttachment::backendFormat() const { | |
| return GrBackendFormats::MakeGL(GrGLFormatToEnum(fFormat), GR_GL_TEXTURE_NONE); | |
| } | |
| void GrGLAttachment::setMemoryBacking(SkTraceMemoryDump* traceMemoryDump, | |
| const SkString& dumpName) const { | |
| SkString renderbuffer_id; | |
| renderbuffer_id.appendU32(this->renderbufferID()); | |
| traceMemoryDump->setMemoryBacking(dumpName.c_str(), "gl_renderbuffer", renderbuffer_id.c_str()); | |
| } | |
| void GrGLAttachment::onSetLabel() { | |
| SkASSERT(fRenderbufferID); | |
| if (!this->getLabel().empty()) { | |
| const std::string label = "_Skia_" + this->getLabel(); | |
| GrGLGpu* glGpu = static_cast<GrGLGpu*>(this->getGpu()); | |
| if (glGpu->glCaps().debugSupport()) { | |
| GR_GL_CALL(glGpu->glInterface(), | |
| ObjectLabel(GR_GL_TEXTURE, fRenderbufferID, -1, label.c_str())); | |
| } | |
| } | |
| } |