#define GR_GL_SAMPLES 0x80A9
#define GR_GL_SAMPLE_COVERAGE_VALUE 0x80AA
#define GR_GL_SAMPLE_COVERAGE_INVERT 0x80AB
+#define GR_GL_RENDERBUFFER_COVERAGE_SAMPLES 0x8CAB
+#define GR_GL_RENDERBUFFER_COLOR_SAMPLES 0x8E10
+#define GR_GL_MAX_MULTISAMPLE_COVERAGE_MODES 0x8E11
+#define GR_GL_MULTISAMPLE_COVERAGE_MODES 0x8E12
/* GetTextureParameter */
/* GL_TEXTURE_MAG_FILTER */
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLReadPixelsProc)(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height, GrGLenum format, GrGLenum type, GrGLvoid* pixels);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLRenderbufferStorageProc)(GrGLenum target, GrGLenum internalformat, GrGLsizei width, GrGLsizei height);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLRenderbufferStorageMultisampleProc)(GrGLenum target, GrGLsizei samples, GrGLenum internalformat, GrGLsizei width, GrGLsizei height);
+ typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLRenderbufferStorageMultisampleCoverageProc)(GrGLenum target, GrGLsizei coverageSamples, GrGLsizei colorSamples, GrGLenum internalformat, GrGLsizei width, GrGLsizei height);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLResolveMultisampleFramebufferProc)();
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLScissorProc)(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLShaderSourceProc)(GrGLuint shader, GrGLsizei count, const char** str, const GrGLint* length);
GLPtr<GrGLReadPixelsProc> fReadPixels;
GLPtr<GrGLRenderbufferStorageProc> fRenderbufferStorage;
GLPtr<GrGLRenderbufferStorageMultisampleProc> fRenderbufferStorageMultisample;
+ GLPtr<GrGLRenderbufferStorageMultisampleCoverageProc> fRenderbufferStorageMultisampleCoverage;
GLPtr<GrGLResolveMultisampleFramebufferProc> fResolveMultisampleFramebuffer;
GLPtr<GrGLScissorProc> fScissor;
GLPtr<GrGLShaderSourceProc> fShaderSource;
#include "GrGLCaps.h"
#include "GrGLContextInfo.h"
+#include "SkTSearch.h"
GrGLCaps::GrGLCaps() {
this->reset();
fStencilFormats.reset();
fStencilVerifiedColorConfigs.reset();
fMSFBOType = kNone_MSFBOType;
+ fCoverageAAType = kNone_CoverageAAType;
fMaxFragmentUniformVectors = 0;
fRGBA8RenderbufferSupport = false;
fBGRAFormatSupport = false;
fStencilVerifiedColorConfigs = caps.fStencilVerifiedColorConfigs;
fMaxFragmentUniformVectors = caps.fMaxFragmentUniformVectors;
fMSFBOType = caps.fMSFBOType;
+ fCoverageAAType = caps.fCoverageAAType;
+ fMSAACoverageModes = caps.fMSAACoverageModes;
fRGBA8RenderbufferSupport = caps.fRGBA8RenderbufferSupport;
fBGRAFormatSupport = caps.fBGRAFormatSupport;
fBGRAIsInternalFormat = caps.fBGRAIsInternalFormat;
this->initStencilFormats(ctxInfo);
}
+namespace {
+int coverage_mode_compare(const GrGLCaps::MSAACoverageMode* left,
+ const GrGLCaps::MSAACoverageMode* right) {
+ if (left->fCoverageSampleCnt < right->fCoverageSampleCnt) {
+ return -1;
+ } else if (right->fCoverageSampleCnt < left->fCoverageSampleCnt) {
+ return 1;
+ } else if (left->fColorSampleCnt < right->fColorSampleCnt) {
+ return -1;
+ } else if (right->fColorSampleCnt < left->fColorSampleCnt) {
+ return 1;
+ }
+ return 0;
+}
+}
+
void GrGLCaps::initFSAASupport(const GrGLContextInfo& ctxInfo) {
fMSFBOType = kNone_MSFBOType;
// and fbo_blit extensions.
fMSFBOType = kDesktopEXT_MSFBOType;
} else if (ctxInfo.hasExtension("GL_APPLE_framebuffer_multisample")) {
- fMSFBOType = kAppleES_MSFBOType;
- }
+ fMSFBOType = kAppleES_MSFBOType;
+ }
} else {
if ((ctxInfo.version() >= GR_GL_VER(3,0)) ||
ctxInfo.hasExtension("GL_ARB_framebuffer_object")) {
ctxInfo.hasExtension("GL_EXT_framebuffer_blit")) {
fMSFBOType = GrGLCaps::kDesktopEXT_MSFBOType;
}
+ // TODO: We could populate fMSAACoverageModes using GetInternalformativ
+ // on GL 4.2+. It's format-specific, though. See also
+ // http://code.google.com/p/skia/issues/detail?id=470 about using actual
+ // rather than requested sample counts in cache key.
+ if (ctxInfo.hasExtension("GL_NV_framebuffer_multisample_coverage")) {
+ fCoverageAAType = kNVDesktop_CoverageAAType;
+ GrGLint count;
+ GR_GL_GetIntegerv(ctxInfo.interface(),
+ GR_GL_MAX_MULTISAMPLE_COVERAGE_MODES,
+ &count);
+ fMSAACoverageModes.setCount(count);
+ GR_GL_GetIntegerv(ctxInfo.interface(),
+ GR_GL_MULTISAMPLE_COVERAGE_MODES,
+ (int*)&fMSAACoverageModes[0]);
+ // The NV driver seems to return the modes already sorted but the
+ // spec doesn't require this. So we sort.
+ SkQSortCompareProc compareProc =
+ reinterpret_cast<SkQSortCompareProc>(&coverage_mode_compare);
+ SkQSort(&fMSAACoverageModes[0],
+ count,
+ sizeof(MSAACoverageMode),
+ compareProc);
+ }
+ }
+}
+
+const GrGLCaps::MSAACoverageMode& GrGLCaps::getMSAACoverageMode(
+ int desiredSampleCount) const {
+ static const MSAACoverageMode kNoneMode = {0, 0};
+ if (0 == fMSAACoverageModes.count()) {
+ return kNoneMode;
+ } else {
+ GrAssert(kNone_CoverageAAType != fCoverageAAType);
+ int max = (fMSAACoverageModes.end() - 1)->fCoverageSampleCnt;
+ desiredSampleCount = GrMin(desiredSampleCount, max);
+ MSAACoverageMode desiredMode = {desiredSampleCount, 0};
+ int idx = SkTSearch<MSAACoverageMode>(&fMSAACoverageModes[0],
+ fMSAACoverageModes.count(),
+ desiredMode,
+ sizeof(MSAACoverageMode),
+ &coverage_mode_compare);
+ if (idx < 0) {
+ idx = ~idx;
+ }
+ GrAssert(idx >= 0 && idx < fMSAACoverageModes.count());
+ return fMSAACoverageModes[idx];
}
}
typedef GrGLStencilBuffer::Format StencilFormat;
/**
+ * Represents a supported multisampling/coverage-sampling mode.
+ */
+ struct MSAACoverageMode {
+ // "Coverage samples" includes samples that actually have color, depth,
+ // stencil, ... as well as those that don't (coverage only). All samples
+ // are coverage samples. (We're using the word "coverage sample" to
+ // match the NV extension language.)
+ int fCoverageSampleCnt;
+
+ // Color samples are samples that store data values (color, stencil,
+ // depth) rather than just representing coverage. They are a subset
+ // of coverage samples. (Again the wording was chosen to match the
+ // extension.)
+ int fColorSampleCnt;
+ };
+
+ /**
* The type of MSAA for FBOs supported. Different extensions have different
* semantics of how / when a resolve is performed.
*/
kAppleES_MSFBOType,
};
+ enum CoverageAAType {
+ /**
+ * No coverage sample support
+ */
+ kNone_CoverageAAType,
+
+ /**
+ * GL_NV_framebuffer_multisample_coverage
+ */
+ kNVDesktop_CoverageAAType,
+ };
+
/**
* Creates a GrGLCaps that advertises no support for any extensions,
* formats, etc. Call init to initialize from a GrGLContextInfo.
MSFBOType msFBOType() const { return fMSFBOType; }
/**
+ * Reports the type of coverage sample AA support.
+ */
+ CoverageAAType coverageAAType() const { return fCoverageAAType; }
+
+ /**
+ * Chooses a supported coverage mode based on a desired sample count. The
+ * desired sample count is rounded up the next supported coverage sample
+ * count unless a it is larger than the max in which case it is rounded
+ * down. Once a coverage sample count is decided, the supported mode with
+ * the fewest color samples is chosen.
+ */
+ const MSAACoverageMode& getMSAACoverageMode(int desiredSampleCount) const;
+
+ /**
* Prints the caps info using GrPrintf.
*/
void print() const;
int fMaxFragmentUniformVectors;
MSFBOType fMSFBOType;
+ CoverageAAType fCoverageAAType;
+ SkTDArray<MSAACoverageMode> fMSAACoverageModes;
bool fRGBA8RenderbufferSupport : 1;
bool fBGRAFormatSupport : 1;
return succeeded;
}
+namespace {
+bool renderbuffer_storage_msaa(GrGLContextInfo& ctxInfo,
+ int sampleCount,
+ GrGLenum format,
+ int width, int height) {
+ CLEAR_ERROR_BEFORE_ALLOC(ctxInfo.interface());
+ GrAssert(GrGLCaps::kNone_MSFBOType != ctxInfo.caps().msFBOType());
+ bool created = false;
+ if (GrGLCaps::kNVDesktop_CoverageAAType ==
+ ctxInfo.caps().coverageAAType()) {
+ const GrGLCaps::MSAACoverageMode& mode =
+ ctxInfo.caps().getMSAACoverageMode(sampleCount);
+ GL_ALLOC_CALL(ctxInfo.interface(),
+ RenderbufferStorageMultisampleCoverage(GR_GL_RENDERBUFFER,
+ mode.fCoverageSampleCnt,
+ mode.fColorSampleCnt,
+ format,
+ width, height));
+ created = (GR_GL_NO_ERROR == CHECK_ALLOC_ERROR(ctxInfo.interface()));
+ }
+ if (!created) {
+ GL_ALLOC_CALL(ctxInfo.interface(),
+ RenderbufferStorageMultisample(GR_GL_RENDERBUFFER,
+ sampleCount,
+ format,
+ width, height));
+ created = (GR_GL_NO_ERROR == CHECK_ALLOC_ERROR(ctxInfo.interface()));
+ }
+ return created;
+}
+}
+
bool GrGpuGL::createRenderTargetObjects(int width, int height,
GrGLuint texID,
GrGLRenderTarget::Desc* desc) {
desc->fOwnIDs = true;
GrGLenum status;
- GrGLint err;
GrGLenum msColorFormat = 0; // suppress warning
GrAssert(desc->fSampleCnt > 1);
GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER,
desc->fMSColorRenderbufferID));
- CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
- GL_ALLOC_CALL(this->glInterface(),
- RenderbufferStorageMultisample(GR_GL_RENDERBUFFER,
- desc->fSampleCnt,
- msColorFormat,
- width, height));
- err = CHECK_ALLOC_ERROR(this->glInterface());
- if (err != GR_GL_NO_ERROR) {
+ if (!renderbuffer_storage_msaa(fGLContextInfo,
+ desc->fSampleCnt,
+ msColorFormat,
+ width, height)) {
goto FAILED;
}
GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, desc->fRTFBOID));
CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
// we do this "if" so that we don't call the multisample
// version on a GL that doesn't have an MSAA extension.
- if (samples > 1) {
- GL_ALLOC_CALL(this->glInterface(),
- RenderbufferStorageMultisample(GR_GL_RENDERBUFFER,
- samples,
- sFmt.fInternalFormat,
- width, height));
+ bool created;
+ if (samples > 0) {
+ created = renderbuffer_storage_msaa(fGLContextInfo,
+ samples,
+ sFmt.fInternalFormat,
+ width, height);
} else {
GL_ALLOC_CALL(this->glInterface(),
RenderbufferStorage(GR_GL_RENDERBUFFER,
sFmt.fInternalFormat,
width, height));
+ created =
+ (GR_GL_NO_ERROR == CHECK_ALLOC_ERROR(this->glInterface()));
}
-
- GrGLenum err = CHECK_ALLOC_ERROR(this->glInterface());
- if (err == GR_GL_NO_ERROR) {
- // After sized formats we attempt an unsized format and take whatever
- // sizes GL gives us. In that case we query for the size.
+ if (created) {
+ // After sized formats we attempt an unsized format and take
+ // whatever sizes GL gives us. In that case we query for the size.
GrGLStencilBuffer::Format format = sFmt;
get_stencil_rb_sizes(this->glInterface(), sbID, &format);
sb = new GrGLStencilBuffer(this, sbID, width, height,
interface->fPixelStorei = glPixelStorei;
interface->fReadBuffer = glReadBuffer;
interface->fReadPixels = glReadPixels;
+ if (GrGLHasExtensionFromString("GL_NV_framebuffer_multisample_coverage",
+ extString)) {
+ GR_GL_GET_PROC_SUFFIX(RenderbufferStorageMultisampleCoverage, NV);
+ }
interface->fScissor = glScissor;
GR_GL_GET_PROC(ShaderSource);
interface->fStencilFunc = glStencilFunc;
GR_GL_GET_PROC(GetShaderiv);
GR_GL_GET_PROC(GetUniformLocation);
GR_GL_GET_PROC(LinkProgram);
+ if (GrGLHasExtensionFromString("GL_NV_framebuffer_multisample_coverage", extString)) {
+ GR_GL_GET_PROC_SUFFIX(RenderbufferStorageMultisampleCoverage, NV);
+ }
GR_GL_GET_PROC(ShaderSource);
GR_GL_GET_PROC(StencilFuncSeparate);
GR_GL_GET_PROC(StencilMaskSeparate);