diff options
author | bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2011-09-22 21:01:31 +0000 |
---|---|---|
committer | bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2011-09-22 21:01:31 +0000 |
commit | 18c9c198f571997463d9a7134dbd88298e592ec2 (patch) | |
tree | aa66d25ecdc1d33dd9c4c7e943b1ca43acd0f13f /gpu/src | |
parent | f1fd30da32f14e6c58b10903267afb937ee64888 (diff) |
Put caps in a struct, move up to GrDrawTarget
Review URL: http://codereview.appspot.com/5088049
git-svn-id: http://skia.googlecode.com/svn/trunk@2314 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'gpu/src')
-rw-r--r-- | gpu/src/GrAAHairLinePathRenderer.cpp | 2 | ||||
-rw-r--r-- | gpu/src/GrBufferAllocPool.cpp | 6 | ||||
-rw-r--r-- | gpu/src/GrContext.cpp | 38 | ||||
-rw-r--r-- | gpu/src/GrDrawTarget.cpp | 20 | ||||
-rw-r--r-- | gpu/src/GrDrawTarget.h | 37 | ||||
-rw-r--r-- | gpu/src/GrGLIndexBuffer.cpp | 6 | ||||
-rw-r--r-- | gpu/src/GrGLVertexBuffer.cpp | 6 | ||||
-rw-r--r-- | gpu/src/GrGpu.cpp | 3 | ||||
-rw-r--r-- | gpu/src/GrGpu.h | 139 | ||||
-rw-r--r-- | gpu/src/GrGpuGL.cpp | 480 | ||||
-rw-r--r-- | gpu/src/GrGpuGL.h | 64 | ||||
-rw-r--r-- | gpu/src/GrGpuGLFixed.cpp | 3 | ||||
-rw-r--r-- | gpu/src/GrGpuGLShaders.cpp | 16 | ||||
-rw-r--r-- | gpu/src/GrInOrderDrawBuffer.cpp | 12 | ||||
-rw-r--r-- | gpu/src/GrPathRendererChain.cpp | 6 |
15 files changed, 382 insertions, 456 deletions
diff --git a/gpu/src/GrAAHairLinePathRenderer.cpp b/gpu/src/GrAAHairLinePathRenderer.cpp index 8349fa77f1..4d05a6bb7d 100644 --- a/gpu/src/GrAAHairLinePathRenderer.cpp +++ b/gpu/src/GrAAHairLinePathRenderer.cpp @@ -87,7 +87,7 @@ GrPathRenderer* GrAAHairLinePathRenderer::Create(GrContext* context) { } bool GrAAHairLinePathRenderer::CanBeUsed(const GrContext* context) { - return context->getGpu()->supportsShaderDerivatives(); + return context->getGpu()->getCaps().fShaderDerivativeSupport; } diff --git a/gpu/src/GrBufferAllocPool.cpp b/gpu/src/GrBufferAllocPool.cpp index 667e43789b..715d4a9bef 100644 --- a/gpu/src/GrBufferAllocPool.cpp +++ b/gpu/src/GrBufferAllocPool.cpp @@ -91,7 +91,7 @@ void GrBufferAllocPool::reset() { fFirstPreallocBuffer = (fFirstPreallocBuffer + fPreallocBuffersInUse) % fPreallocBuffers.count(); } - fCpuData.reset(fGpu->supportsBufferLocking() ? 0 : fMinBlockSize); + fCpuData.reset(fGpu->getCaps().fBufferLockSupport ? 0 : fMinBlockSize); GrAssert(0 == fPreallocBuffersInUse); VALIDATE(); } @@ -276,7 +276,7 @@ bool GrBufferAllocPool::createBlock(size_t requestSize) { GrAssert(NULL == fBufferPtr); - if (fGpu->supportsBufferLocking() && + if (fGpu->getCaps().fBufferLockSupport && size > GR_GEOM_BUFFER_LOCK_THRESHOLD && (!fFrequentResetHint || requestSize > GR_GEOM_BUFFER_LOCK_THRESHOLD)) { fBufferPtr = block.fBuffer->lock(); @@ -318,7 +318,7 @@ void GrBufferAllocPool::flushCpuData(GrGeometryBuffer* buffer, GrAssert(flushSize <= buffer->sizeInBytes()); bool updated = false; - if (fGpu->supportsBufferLocking() && + if (fGpu->getCaps().fBufferLockSupport && flushSize > GR_GEOM_BUFFER_LOCK_THRESHOLD) { void* data = buffer->lock(); if (NULL != data) { diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp index 6de3169415..ee38d725bc 100644 --- a/gpu/src/GrContext.cpp +++ b/gpu/src/GrContext.cpp @@ -166,13 +166,13 @@ bool gen_texture_key_values(const GrGpu* gpu, // we assume we only need 16 bits of width and height // assert that texture creation will fail anyway if this assumption // would cause key collisions. - GrAssert(gpu->maxTextureSize() <= SK_MaxU16); + GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16); v[0] = clientKey & 0xffffffffUL; v[1] = (clientKey >> 32) & 0xffffffffUL; v[2] = width | (height << 16); v[3] = 0; - if (!gpu->npotTextureTileSupport()) { + if (!gpu->getCaps().fNPOTTextureTileSupport) { bool isPow2 = GrIsPow2(width) && GrIsPow2(height); bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) || @@ -310,10 +310,12 @@ GrContext::TextureCacheEntry GrContext::createAndLockTexture(TextureKey key, rtDesc.fFlags = rtDesc.fFlags | kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; - rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth, - fGpu->minRenderTargetWidth())); - rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight, - fGpu->minRenderTargetHeight())); + rtDesc.fWidth = + GrNextPow2(GrMax<int>(desc.fWidth, + fGpu->getCaps().fMinRenderTargetWidth)); + rtDesc.fHeight = + GrNextPow2(GrMax<int>(desc.fHeight, + fGpu->getCaps().fMinRenderTargetHeight)); GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0); @@ -510,11 +512,11 @@ void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) { } int GrContext::getMaxTextureSize() const { - return fGpu->maxTextureSize(); + return fGpu->getCaps().fMaxTextureSize; } int GrContext::getMaxRenderTargetSize() const { - return fGpu->maxRenderTargetSize(); + return fGpu->getCaps().fMaxRenderTargetSize; } /////////////////////////////////////////////////////////////////////////////// @@ -541,21 +543,21 @@ GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler, int width, int height) const { - if (!fGpu->supports8BitPalette()) { + const GrDrawTarget::Caps& caps = fGpu->getCaps(); + if (!caps.f8BitPaletteSupport) { return false; } - bool isPow2 = GrIsPow2(width) && GrIsPow2(height); if (!isPow2) { - if (!fGpu->npotTextureSupport()) { + if (!caps.fNPOTTextureSupport) { return false; } bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode || sampler.getWrapY() != GrSamplerState::kClamp_WrapMode; - if (tiled && !fGpu->npotTextureTileSupport()) { + if (tiled && !caps.fNPOTTextureTileSupport) { return false; } } @@ -659,7 +661,7 @@ bool GrContext::doOffscreenAA(GrDrawTarget* target, // Line primitves are always rasterized as 1 pixel wide. // Super-sampling would make them too thin but MSAA would be OK. if (isHairLines && - (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA())) { + (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) { return false; } if (target->getRenderTarget()->isMultisampled()) { @@ -708,12 +710,12 @@ bool GrContext::prepareForOffscreenAA(GrDrawTarget* target, desc.fFormat = kRGBA_8888_GrPixelConfig; - if (PREFER_MSAA_OFFSCREEN_AA && fGpu->supportsFullsceneAA()) { + if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) { record->fDownsample = OffscreenRecord::kFSAA_Downsample; record->fScale = 1; desc.fAALevel = kMed_GrAALevel; } else { - record->fDownsample = (fGpu->supportsShaders()) ? + record->fDownsample = fGpu->getCaps().fShaderSupport ? OffscreenRecord::k4x4SinglePass_Downsample : OffscreenRecord::k4x4TwoPass_Downsample; record->fScale = OFFSCREEN_SSAA_SCALE; @@ -1519,7 +1521,7 @@ void GrContext::drawPath(const GrPaint& paint, const GrPath& path, //////////////////////////////////////////////////////////////////////////////// bool GrContext::supportsShaders() const { - return fGpu->supportsShaders(); + return fGpu->getCaps().fShaderSupport; } void GrContext::flush(int flagsBitfield) { @@ -1773,8 +1775,8 @@ GrContext::GrContext(GrGpu* gpu) { fAAFillRectIndexBuffer = NULL; fAAStrokeRectIndexBuffer = NULL; - int gpuMaxOffscreen = fGpu->maxRenderTargetSize(); - if (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA()) { + int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize; + if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) { gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE; } fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen); diff --git a/gpu/src/GrDrawTarget.cpp b/gpu/src/GrDrawTarget.cpp index 51cff6dec3..bfcc07de80 100644 --- a/gpu/src/GrDrawTarget.cpp +++ b/gpu/src/GrDrawTarget.cpp @@ -1041,3 +1041,23 @@ void GrDrawTarget::AutoReleaseGeometry::reset() { fIndices = NULL; } +void GrDrawTarget::Caps::print() const { + static const char* gNY[] = {"NO", "YES"}; + GrPrintf("8 Bit Palette Support : %s\n", gNY[f8BitPaletteSupport]); + GrPrintf("NPOT Texture Support : %s\n", gNY[fNPOTTextureSupport]); + GrPrintf("NPOT Texture Tile Support : %s\n", gNY[fNPOTTextureTileSupport]); + GrPrintf("NPOT Render Target Support : %s\n", gNY[fNPOTRenderTargetSupport]); + GrPrintf("Two Sided Stencil Support : %s\n", gNY[fTwoSidedStencilSupport]); + GrPrintf("Stencil Wrap Ops Support : %s\n", gNY[fStencilWrapOpsSupport]); + GrPrintf("HW AA Lines Support : %s\n", gNY[fHWAALineSupport]); + GrPrintf("Shader Support : %s\n", gNY[fShaderSupport]); + GrPrintf("Shader Derivative Support : %s\n", gNY[fShaderDerivativeSupport]); + GrPrintf("FSAA Support : %s\n", gNY[fFSAASupport]); + GrPrintf("Dual Source Blending Support: %s\n", gNY[fDualSourceBlendingSupport]); + GrPrintf("Buffer Lock Support : %s\n", gNY[fBufferLockSupport]); + GrPrintf("Min Render Target Width : %d\n", fMinRenderTargetWidth); + GrPrintf("Min Render Target Height : %d\n", fMinRenderTargetHeight); + GrPrintf("Max Texture Size : %d\n", fMaxTextureSize); + GrPrintf("Max Render Target Size : %d\n", fMaxRenderTargetSize); +} + diff --git a/gpu/src/GrDrawTarget.h b/gpu/src/GrDrawTarget.h index 1d61a18fd6..a57ff81c0a 100644 --- a/gpu/src/GrDrawTarget.h +++ b/gpu/src/GrDrawTarget.h @@ -30,6 +30,35 @@ class GrIndexBuffer; class GrDrawTarget : public GrRefCnt { public: /** + * Represents the draw target capabilities. + */ + struct Caps { + Caps() { memset(this, 0, sizeof(Caps)); } + Caps(const Caps& c) { *this = c; } + Caps& operator= (const Caps& c) { + memcpy(this, &c, sizeof(Caps)); + return *this; + } + void print() const; + bool f8BitPaletteSupport : 1; + bool fNPOTTextureSupport : 1; + bool fNPOTTextureTileSupport : 1; + bool fNPOTRenderTargetSupport : 1; + bool fTwoSidedStencilSupport : 1; + bool fStencilWrapOpsSupport : 1; + bool fHWAALineSupport : 1; + bool fShaderSupport : 1; + bool fShaderDerivativeSupport : 1; + bool fFSAASupport : 1; + bool fDualSourceBlendingSupport : 1; + bool fBufferLockSupport : 1; + int fMinRenderTargetWidth; + int fMinRenderTargetHeight; + int fMaxRenderTargetSize; + int fMaxTextureSize; + }; + + /** * Number of texture stages. Each stage takes as input a color and * 2D texture coordinates. The color input to the first enabled stage is the * per-vertex color or the constant color (setColor/setAlpha) if there are @@ -48,7 +77,6 @@ public: kMaxTexCoords = kNumStages }; - /** * The absolute maximum number of edges that may be specified for * a single draw call when performing edge antialiasing. This is used for @@ -197,6 +225,11 @@ public: virtual ~GrDrawTarget(); /** + * Gets the capabilities of the draw target. + */ + const Caps& getCaps() const { return fCaps; } + + /** * Sets the current clip to the region specified by clip. All draws will be * clipped against this clip if kClip_StateBit is enabled. * @@ -1307,6 +1340,8 @@ protected: DrState fCurrDrawState; + Caps fCaps; + private: // called when setting a new vert/idx source to unref prev vb/ib void releasePreviousVertexSource(); diff --git a/gpu/src/GrGLIndexBuffer.cpp b/gpu/src/GrGLIndexBuffer.cpp index 27915273fe..084a4c61b0 100644 --- a/gpu/src/GrGLIndexBuffer.cpp +++ b/gpu/src/GrGLIndexBuffer.cpp @@ -51,7 +51,7 @@ GrGLuint GrGLIndexBuffer::bufferID() const { void* GrGLIndexBuffer::lock() { GrAssert(fBufferID); GrAssert(!isLocked()); - if (GPUGL->supportsBufferLocking()) { + if (this->getGpu()->getCaps().fBufferLockSupport) { this->bind(); // Let driver know it can discard the old data GL_CALL(BufferData(GR_GL_ELEMENT_ARRAY_BUFFER, @@ -76,7 +76,7 @@ void* GrGLIndexBuffer::lockPtr() const { void GrGLIndexBuffer::unlock() { GrAssert(fBufferID); GrAssert(isLocked()); - GrAssert(GPUGL->supportsBufferLocking()); + GrAssert(this->getGpu()->getCaps().fBufferLockSupport); this->bind(); GL_CALL(UnmapBuffer(GR_GL_ELEMENT_ARRAY_BUFFER)); @@ -85,7 +85,7 @@ void GrGLIndexBuffer::unlock() { bool GrGLIndexBuffer::isLocked() const { #if GR_DEBUG - if (this->isValid() && GPUGL->supportsBufferLocking()) { + if (this->isValid() && this->getGpu()->getCaps().fBufferLockSupport) { this->bind(); GrGLint mapped; GL_CALL(GetBufferParameteriv(GR_GL_ELEMENT_ARRAY_BUFFER, diff --git a/gpu/src/GrGLVertexBuffer.cpp b/gpu/src/GrGLVertexBuffer.cpp index 2d5aee0a37..c542602a9b 100644 --- a/gpu/src/GrGLVertexBuffer.cpp +++ b/gpu/src/GrGLVertexBuffer.cpp @@ -50,7 +50,7 @@ GrGLuint GrGLVertexBuffer::bufferID() const { void* GrGLVertexBuffer::lock() { GrAssert(fBufferID); GrAssert(!isLocked()); - if (GPUGL->supportsBufferLocking()) { + if (this->getGpu()->getCaps().fBufferLockSupport) { this->bind(); // Let driver know it can discard the old data GL_CALL(BufferData(GR_GL_ARRAY_BUFFER, this->sizeInBytes(), NULL, @@ -72,7 +72,7 @@ void GrGLVertexBuffer::unlock() { GrAssert(fBufferID); GrAssert(isLocked()); - GrAssert(GPUGL->supportsBufferLocking()); + GrAssert(this->getGpu()->getCaps().fBufferLockSupport); this->bind(); GL_CALL(UnmapBuffer(GR_GL_ARRAY_BUFFER)); @@ -82,7 +82,7 @@ void GrGLVertexBuffer::unlock() { bool GrGLVertexBuffer::isLocked() const { GrAssert(!this->isValid() || fBufferID); #if GR_DEBUG - if (this->isValid() && GPUGL->supportsBufferLocking()) { + if (this->isValid() && this->getGpu()->getCaps().fBufferLockSupport) { GrGLint mapped; this->bind(); GL_CALL(GetBufferParameteriv(GR_GL_ARRAY_BUFFER, diff --git a/gpu/src/GrGpu.cpp b/gpu/src/GrGpu.cpp index b338d05e46..91e659d20d 100644 --- a/gpu/src/GrGpu.cpp +++ b/gpu/src/GrGpu.cpp @@ -31,8 +31,7 @@ extern void gr_run_unittests(); #define DEBUG_INVAL_START_IDX -1 GrGpu::GrGpu() - : f8bitPaletteSupport(false) - , fContext(NULL) + : fContext(NULL) , fVertexPool(NULL) , fIndexPool(NULL) , fVertexPoolUseCnt(0) diff --git a/gpu/src/GrGpu.h b/gpu/src/GrGpu.h index e970554bcf..9ecb4b0619 100644 --- a/gpu/src/GrGpu.h +++ b/gpu/src/GrGpu.h @@ -54,6 +54,7 @@ struct GrGpuStats { class GrGpu : public GrDrawTarget { public: + /** * Additional blend coeffecients for dual source blending, not exposed * through GrPaint/GrContext. @@ -147,118 +148,6 @@ public: GrIndexBuffer* createIndexBuffer(uint32_t size, bool dynamic); /** - * Are 8 bit paletted textures supported. - * - * @return true if 8bit palette textures are supported, false otherwise - */ - bool supports8BitPalette() const { return f8bitPaletteSupport; } - - /** - * returns true if two sided stenciling is supported. If false then only - * the front face values of the GrStencilSettings - * @return true if only a single stencil pass is needed. - */ - bool supportsTwoSidedStencil() const - { return fTwoSidedStencilSupport; } - - /** - * returns true if stencil wrap is supported. If false then - * kIncWrap_StencilOp and kDecWrap_StencilOp are treated as - * kIncClamp_StencilOp and kDecClamp_StencilOp, respectively. - * @return true if stencil wrap ops are supported. - */ - bool supportsStencilWrapOps() const - { return fStencilWrapOpsSupport; } - - /** - * Checks whether locking vertex and index buffers is supported. - * - * @return true if locking is supported. - */ - bool supportsBufferLocking() const { return fBufferLockSupport; } - - /** - * Does the 3D API support anti-aliased lines. If so then line primitive - * types will use this functionality when the AA state flag is set. - */ - bool supportsHWAALines() const { return fAALineSupport; } - - /** - * Are shaders supported. - */ - bool supportsShaders() const { return fShaderSupport; } - - /** - * Are derivative instructions supported in fragment shaders - */ - bool supportsShaderDerivatives() const { return fShaderDerivativeSupport; } - - /** - * Does the subclass support GrSamplerState::k4x4Downsample_Filter - */ - bool supports4x4DownsampleFilter() const { return f4X4DownsampleFilterSupport; } - - /** - * Does this instance support dual-source blending? Required for proper - * blending with partial coverage with certain blend modes (dst coeff is - * not 1, ISA, or ISC) - */ - bool supportsDualSourceBlending() const { - return fDualSourceBlendingSupport; - } - - /** - * Gets the minimum width of a render target. If a texture/rt is created - * with a width less than this size the GrGpu object will clamp it to this - * value. - */ - int minRenderTargetWidth() const { return fMinRenderTargetWidth; } - - /** - * Gets the minimum width of a render target. If a texture/rt is created - * with a height less than this size the GrGpu object will clamp it to this - * value. - */ - int minRenderTargetHeight() const { return fMinRenderTargetHeight; } - - /** - * Reports whether full scene anti-aliasing is supported. - */ - bool supportsFullsceneAA() const { return fFSAASupport; } - - /** - * Returns true if NPOT textures can be created - * - * @return true if NPOT textures can be created - */ - bool npotTextureSupport() const { return fNPOTTextureSupport; } - - /** - * Returns true if NPOT textures can be repeat/mirror tiled. - * - * @return true if NPOT textures can be tiled - */ - bool npotTextureTileSupport() const { return fNPOTTextureTileSupport; } - - /** - * Returns true if a NPOT texture can be a rendertarget - * - * @return the true if NPOT texture/rendertarget can be created. - */ - bool npotRenderTargetSupport() const { return fNPOTRenderTargetSupport; } - - /** - * Gets the largest allowed width and height of a texture. - */ - int maxTextureSize() const { return fMaxTextureSize; } - /** - * Gets the largest allowed width and height of a render target. - */ - int maxRenderTargetSize() const { return fMaxRenderTargetSize; } - - virtual void clear(const GrIRect* rect, GrColor color); - - /** * Returns an index buffer that can be used to render quads. * Six indices per quad: 0, 1, 2, 0, 2, 3, etc. * The max number of quads can be queried using GrIndexBuffer::maxQuads(). @@ -331,6 +220,7 @@ public: // GrDrawTarget overrides virtual bool willUseHWAALines() const; + virtual void clear(const GrIRect* rect, GrColor color); protected: enum PrivateStateBits { @@ -363,31 +253,6 @@ protected: // and the client isn't using the stencil test. static const GrStencilSettings gClipStencilSettings; - // defaults to false, subclass can set true to support palleted textures - bool f8bitPaletteSupport; - - // set by subclass - bool fNPOTTextureSupport; - bool fNPOTTextureTileSupport; - bool fNPOTRenderTargetSupport; - bool fTwoSidedStencilSupport; - bool fStencilWrapOpsSupport; - bool fAALineSupport; - bool fShaderSupport; - bool fShaderDerivativeSupport; - bool fFSAASupport; - bool f4X4DownsampleFilterSupport; // supports GrSamplerState::k4x4Downsample_Filter - bool fDualSourceBlendingSupport; - - // set by subclass to true if index and vertex buffers can be locked, false - // otherwise. - bool fBufferLockSupport; - - // set by subclass - int fMinRenderTargetWidth; - int fMinRenderTargetHeight; - int fMaxRenderTargetSize; - int fMaxTextureSize; GrGpuStats fStats; diff --git a/gpu/src/GrGpuGL.cpp b/gpu/src/GrGpuGL.cpp index 9906037f5d..f1d6f8a6b9 100644 --- a/gpu/src/GrGpuGL.cpp +++ b/gpu/src/GrGpuGL.cpp @@ -257,9 +257,9 @@ static int probe_for_min_render_target_width(const GrGLInterface* gl, return minRenderTargetWidth; } +GrGpuGL::GrGpuGL(const GrGLInterface* gl, GrGLBinding glBinding) { -GrGpuGL::GrGpuGL(const GrGLInterface* gl, GrGLBinding glBinding) - : fStencilFormats(8) { + fPrintedCaps = false; gl->ref(); fGL = gl; @@ -303,148 +303,86 @@ GrGpuGL::GrGpuGL(const GrGLInterface* gl, GrGLBinding glBinding) this->resetDirtyFlags(); + this->initCaps(); + + fLastSuccessfulStencilFmtIdx = 0; +} + +GrGpuGL::~GrGpuGL() { + // This subclass must do this before the base class destructor runs + // since we will unref the GrGLInterface. + this->releaseResources(); + fGL->unref(); +} + +/////////////////////////////////////////////////////////////////////////////// + +static const GrGLuint kUnknownBitCount = ~0; + +void GrGpuGL::initCaps() { GrGLint maxTextureUnits; // check FS and fixed-function texture unit limits // we only use textures in the fragment stage currently. // checks are > to make sure we have a spare unit. if (kES1_GrGLBinding != this->glBinding()) { - GR_GL_GetIntegerv(gl, GR_GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits); + GR_GL_GetIntegerv(fGL, GR_GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits); GrAssert(maxTextureUnits > kNumStages); } if (kES2_GrGLBinding != this->glBinding()) { - GR_GL_GetIntegerv(gl, GR_GL_MAX_TEXTURE_UNITS, &maxTextureUnits); + GR_GL_GetIntegerv(fGL, GR_GL_MAX_TEXTURE_UNITS, &maxTextureUnits); GrAssert(maxTextureUnits > kNumStages); } if (kES2_GrGLBinding == this->glBinding()) { - GR_GL_GetIntegerv(gl, GR_GL_MAX_FRAGMENT_UNIFORM_VECTORS, - &fMaxFragmentUniformVectors); + GR_GL_GetIntegerv(fGL, GR_GL_MAX_FRAGMENT_UNIFORM_VECTORS, + &fGLCaps.fMaxFragmentUniformVectors); } else if (kDesktop_GrGLBinding != this->glBinding()) { GrGLint max; - GR_GL_GetIntegerv(gl, GR_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &max); - fMaxFragmentUniformVectors = max / 4; + GR_GL_GetIntegerv(fGL, GR_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &max); + fGLCaps.fMaxFragmentUniformVectors = max / 4; } else { - fMaxFragmentUniformVectors = 16; + fGLCaps.fMaxFragmentUniformVectors = 16; } - //////////////////////////////////////////////////////////////////////////// - // Check for supported features. - - this->setupStencilFormats(); - GrGLint numFormats; - GR_GL_GetIntegerv(gl, GR_GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numFormats); + GR_GL_GetIntegerv(fGL, GR_GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numFormats); SkAutoSTMalloc<10, GrGLint> formats(numFormats); - GR_GL_GetIntegerv(gl, GR_GL_COMPRESSED_TEXTURE_FORMATS, formats); + GR_GL_GetIntegerv(fGL, GR_GL_COMPRESSED_TEXTURE_FORMATS, formats); for (int i = 0; i < numFormats; ++i) { if (formats[i] == GR_GL_PALETTE8_RGBA8) { - f8bitPaletteSupport = true; + fCaps.f8BitPaletteSupport = true; break; } } - if (gPrintStartupSpew) { - GrPrintf("Palette8 support: %s\n", (f8bitPaletteSupport ? "YES" : "NO")); - } - - GR_STATIC_ASSERT(0 == kNone_GrAALevel); - GR_STATIC_ASSERT(1 == kLow_GrAALevel); - GR_STATIC_ASSERT(2 == kMed_GrAALevel); - GR_STATIC_ASSERT(3 == kHigh_GrAALevel); - - memset(fAASamples, 0, sizeof(fAASamples)); - fMSFBOType = kNone_MSFBO; - if (kDesktop_GrGLBinding != this->glBinding()) { - if (this->hasExtension("GL_CHROMIUM_framebuffer_multisample")) { - // chrome's extension is equivalent to the EXT msaa - // and fbo_blit extensions. - fMSFBOType = kDesktopEXT_MSFBO; - } else if (this->hasExtension("GL_APPLE_framebuffer_multisample")) { - fMSFBOType = kAppleES_MSFBO; - } - } else { - if ((fGLVersion >= GR_GL_VER(3,0)) || this->hasExtension("GL_ARB_framebuffer_object")) { - fMSFBOType = kDesktopARB_MSFBO; - } else if (this->hasExtension("GL_EXT_framebuffer_multisample") && - this->hasExtension("GL_EXT_framebuffer_blit")) { - fMSFBOType = kDesktopEXT_MSFBO; - } - } - if (gPrintStartupSpew) { - switch (fMSFBOType) { - case kNone_MSFBO: - GrPrintf("MSAA Support: NONE\n"); - break; - case kDesktopARB_MSFBO: - GrPrintf("MSAA Support: DESKTOP ARB.\n"); - break; - case kDesktopEXT_MSFBO: - GrPrintf("MSAA Support: DESKTOP EXT.\n"); - break; - case kAppleES_MSFBO: - GrPrintf("MSAA Support: APPLE ES.\n"); - break; - } - } - - if (kNone_MSFBO != fMSFBOType) { - GrGLint maxSamples; - GR_GL_GetIntegerv(gl, GR_GL_MAX_SAMPLES, &maxSamples); - if (maxSamples > 1 ) { - fAASamples[kNone_GrAALevel] = 0; - fAASamples[kLow_GrAALevel] = GrMax(2, - GrFixedFloorToInt((GR_FixedHalf) * - maxSamples)); - fAASamples[kMed_GrAALevel] = GrMax(2, - GrFixedFloorToInt(((GR_Fixed1*3)/4) * - maxSamples)); - fAASamples[kHigh_GrAALevel] = maxSamples; - } - if (gPrintStartupSpew) { - GrPrintf("\tMax Samples: %d\n", maxSamples); - } - } - fFSAASupport = fAASamples[kHigh_GrAALevel] > 0; - if (kDesktop_GrGLBinding == this->glBinding()) { - fHasStencilWrap = (fGLVersion >= GR_GL_VER(1,4)) || - this->hasExtension("GL_EXT_stencil_wrap"); + fCaps.fStencilWrapOpsSupport = (fGLVersion >= GR_GL_VER(1,4)) || + this->hasExtension("GL_EXT_stencil_wrap"); } else { - fHasStencilWrap = (fGLVersion >= GR_GL_VER(2,0)) || - this->hasExtension("GL_OES_stencil_wrap"); - } - if (gPrintStartupSpew) { - GrPrintf("Stencil Wrap: %s\n", (fHasStencilWrap ? "YES" : "NO")); + fCaps.fStencilWrapOpsSupport = (fGLVersion >= GR_GL_VER(2,0)) || + this->hasExtension("GL_OES_stencil_wrap"); } if (kDesktop_GrGLBinding == this->glBinding()) { // we could also look for GL_ATI_separate_stencil extension or // GL_EXT_stencil_two_side but they use different function signatures // than GL2.0+ (and than each other). - fTwoSidedStencilSupport = (fGLVersion >= GR_GL_VER(2,0)); + fCaps.fTwoSidedStencilSupport = (fGLVersion >= GR_GL_VER(2,0)); // supported on GL 1.4 and higher or by extension - fStencilWrapOpsSupport = (fGLVersion >= GR_GL_VER(1,4)) || - this->hasExtension("GL_EXT_stencil_wrap"); + fCaps.fStencilWrapOpsSupport = (fGLVersion >= GR_GL_VER(1,4)) || + this->hasExtension("GL_EXT_stencil_wrap"); } else { // ES 2 has two sided stencil but 1.1 doesn't. There doesn't seem to be // an ES1 extension. - fTwoSidedStencilSupport = (fGLVersion >= GR_GL_VER(2,0)); + fCaps.fTwoSidedStencilSupport = (fGLVersion >= GR_GL_VER(2,0)); // stencil wrap support is in ES2, ES1 requires extension. - fStencilWrapOpsSupport = (fGLVersion >= GR_GL_VER(2,0)) || - this->hasExtension("GL_OES_stencil_wrap"); - } - if (gPrintStartupSpew) { - GrPrintf("Stencil Caps: TwoSide: %s, Wrap: %s\n", - (fTwoSidedStencilSupport ? "YES" : "NO"), - (fStencilWrapOpsSupport ? "YES" : "NO")); + fCaps.fStencilWrapOpsSupport = (fGLVersion >= GR_GL_VER(2,0)) || + this->hasExtension("GL_OES_stencil_wrap"); } if (kDesktop_GrGLBinding == this->glBinding()) { - fRGBA8Renderbuffer = true; + fGLCaps.fRGBA8Renderbuffer = true; } else { - fRGBA8Renderbuffer = this->hasExtension("GL_OES_rgb8_rgba8"); - } - if (gPrintStartupSpew) { - GrPrintf("RGBA Renderbuffer: %s\n", (fRGBA8Renderbuffer ? "YES" : "NO")); + fGLCaps.fRGBA8Renderbuffer = this->hasExtension("GL_OES_rgb8_rgba8"); } @@ -455,101 +393,177 @@ GrGpuGL::GrGpuGL(const GrGLInterface* gl, GrGLBinding glBinding) } if (kDesktop_GrGLBinding == this->glBinding()) { - fBufferLockSupport = true; // we require VBO support and the desktop VBO - // extension includes glMapBuffer. + fCaps.fBufferLockSupport = true; // we require VBO support and the desktop VBO + // extension includes glMapBuffer. } else { - fBufferLockSupport = this->hasExtension("GL_OES_mapbuffer"); - } - - if (gPrintStartupSpew) { - GrPrintf("Map Buffer: %s\n", (fBufferLockSupport ? "YES" : "NO")); + fCaps.fBufferLockSupport = this->hasExtension("GL_OES_mapbuffer"); } if (kDesktop_GrGLBinding == this->glBinding()) { if (fGLVersion >= GR_GL_VER(2,0) || this->hasExtension("GL_ARB_texture_non_power_of_two")) { - fNPOTTextureTileSupport = true; - fNPOTTextureSupport = true; + fCaps.fNPOTTextureTileSupport = true; + fCaps.fNPOTTextureSupport = true; } else { - fNPOTTextureTileSupport = false; - fNPOTTextureSupport = false; + fCaps.fNPOTTextureTileSupport = false; + fCaps.fNPOTTextureSupport = false; } } else { if (fGLVersion >= GR_GL_VER(2,0)) { - fNPOTTextureSupport = true; - fNPOTTextureTileSupport = this->hasExtension("GL_OES_texture_npot"); + fCaps.fNPOTTextureSupport = true; + fCaps.fNPOTTextureTileSupport = this->hasExtension("GL_OES_texture_npot"); } else { - fNPOTTextureSupport = + fCaps.fNPOTTextureSupport = this->hasExtension("GL_APPLE_texture_2D_limited_npot"); - fNPOTTextureTileSupport = false; + fCaps.fNPOTTextureTileSupport = false; } } - fAALineSupport = (kDesktop_GrGLBinding == this->glBinding()); + fCaps.fHWAALineSupport = (kDesktop_GrGLBinding == this->glBinding()); //////////////////////////////////////////////////////////////////////////// // Experiments to determine limitations that can't be queried. // TODO: Make these a preprocess that generate some compile time constants. // TODO: probe once at startup, rather than once per context creation. - int expectNPOTTargets = gl->fNPOTRenderTargetSupport; + int expectNPOTTargets = fGL->fNPOTRenderTargetSupport; if (expectNPOTTargets == kProbe_GrGLCapability) { - fNPOTRenderTargetSupport = - probe_for_npot_render_target_support(gl, fNPOTTextureSupport); + fCaps.fNPOTRenderTargetSupport = + probe_for_npot_render_target_support(fGL, fCaps.fNPOTTextureSupport); } else { GrAssert(expectNPOTTargets == 0 || expectNPOTTargets == 1); - fNPOTRenderTargetSupport = static_cast<bool>(expectNPOTTargets); + fCaps.fNPOTRenderTargetSupport = static_cast<bool>(expectNPOTTargets); } - if (gPrintStartupSpew) { - if (fNPOTTextureSupport) { - GrPrintf("NPOT textures supported\n"); - if (fNPOTTextureTileSupport) { - GrPrintf("NPOT texture tiling supported\n"); - } else { - GrPrintf("NPOT texture tiling NOT supported\n"); - } - if (fNPOTRenderTargetSupport) { - GrPrintf("NPOT render targets supported\n"); - } else { - GrPrintf("NPOT render targets NOT supported\n"); - } - } else { - GrPrintf("NPOT textures NOT supported\n"); - } - } - - GR_GL_GetIntegerv(gl, GR_GL_MAX_TEXTURE_SIZE, &fMaxTextureSize); - GR_GL_GetIntegerv(gl, GR_GL_MAX_RENDERBUFFER_SIZE, &fMaxRenderTargetSize); + GR_GL_GetIntegerv(fGL, GR_GL_MAX_TEXTURE_SIZE, &fCaps.fMaxTextureSize); + GR_GL_GetIntegerv(fGL, GR_GL_MAX_RENDERBUFFER_SIZE, &fCaps.fMaxRenderTargetSize); // Our render targets are always created with textures as the color // attachment, hence this min: - fMaxRenderTargetSize = GrMin(fMaxTextureSize, fMaxRenderTargetSize); + fCaps.fMaxRenderTargetSize = GrMin(fCaps.fMaxTextureSize, fCaps.fMaxRenderTargetSize); - fMinRenderTargetHeight = gl->fMinRenderTargetHeight; - if (fMinRenderTargetHeight == kProbe_GrGLCapability) { - fMinRenderTargetHeight = - probe_for_min_render_target_height(gl,fNPOTRenderTargetSupport, - fMaxRenderTargetSize); + fCaps.fMinRenderTargetHeight = fGL->fMinRenderTargetHeight; + if (fCaps.fMinRenderTargetHeight == kProbe_GrGLCapability) { + fCaps.fMinRenderTargetHeight = + probe_for_min_render_target_height(fGL, fCaps.fNPOTRenderTargetSupport, + fCaps.fMaxRenderTargetSize); } - fMinRenderTargetWidth = gl->fMinRenderTargetWidth; - if (fMinRenderTargetWidth == kProbe_GrGLCapability) { - fMinRenderTargetWidth = - probe_for_min_render_target_width(gl, fNPOTRenderTargetSupport, - fMaxRenderTargetSize); + fCaps.fMinRenderTargetWidth = fGL->fMinRenderTargetWidth; + if (fCaps.fMinRenderTargetWidth == kProbe_GrGLCapability) { + fCaps.fMinRenderTargetWidth = + probe_for_min_render_target_width(fGL, fCaps.fNPOTRenderTargetSupport, + fCaps.fMaxRenderTargetSize); } - fLastSuccessfulStencilFmtIdx = 0; + this->initFSAASupport(); + this->initStencilFormats(); } -GrGpuGL::~GrGpuGL() { - // This subclass must do this before the base class destructor runs - // since we will unref the GrGLInterface. - this->releaseResources(); - fGL->unref(); +void GrGpuGL::initFSAASupport() { + // TODO: Get rid of GrAALevel and use # samples directly. + GR_STATIC_ASSERT(0 == kNone_GrAALevel); + GR_STATIC_ASSERT(1 == kLow_GrAALevel); + GR_STATIC_ASSERT(2 == kMed_GrAALevel); + GR_STATIC_ASSERT(3 == kHigh_GrAALevel); + memset(fGLCaps.fAASamples, 0, sizeof(fGLCaps.fAASamples)); + + fGLCaps.fMSFBOType = GLCaps::kNone_MSFBO; + if (kDesktop_GrGLBinding != this->glBinding()) { + if (this->hasExtension("GL_CHROMIUM_framebuffer_multisample")) { + // chrome's extension is equivalent to the EXT msaa + // and fbo_blit extensions. + fGLCaps.fMSFBOType = GLCaps::kDesktopEXT_MSFBO; + } else if (this->hasExtension("GL_APPLE_framebuffer_multisample")) { + fGLCaps.fMSFBOType = GLCaps::kAppleES_MSFBO; + } + } else { + if ((fGLVersion >= GR_GL_VER(3,0)) || this->hasExtension("GL_ARB_framebuffer_object")) { + fGLCaps.fMSFBOType = GLCaps::kDesktopARB_MSFBO; + } else if (this->hasExtension("GL_EXT_framebuffer_multisample") && + this->hasExtension("GL_EXT_framebuffer_blit")) { + fGLCaps.fMSFBOType = GLCaps::kDesktopEXT_MSFBO; + } + } + + if (GLCaps::kNone_MSFBO != fGLCaps.fMSFBOType) { + GrGLint maxSamples; + GR_GL_GetIntegerv(fGL, GR_GL_MAX_SAMPLES, &maxSamples); + if (maxSamples > 1 ) { + fGLCaps.fAASamples[kNone_GrAALevel] = 0; + fGLCaps.fAASamples[kLow_GrAALevel] = + GrMax(2, GrFixedFloorToInt((GR_FixedHalf) * maxSamples)); + fGLCaps.fAASamples[kMed_GrAALevel] = + GrMax(2, GrFixedFloorToInt(((GR_Fixed1*3)/4) * maxSamples)); + fGLCaps.fAASamples[kHigh_GrAALevel] = maxSamples; + } + } + fCaps.fFSAASupport = fGLCaps.fAASamples[kHigh_GrAALevel] > 0; +} + +void GrGpuGL::initStencilFormats() { + + // Build up list of legal stencil formats (though perhaps not supported on + // the particular gpu/driver) from most preferred to least. + + // these consts are in order of most preferred to least preferred + // we don't bother with GL_STENCIL_INDEX1 or GL_DEPTH32F_STENCIL8 + static const GrGLStencilBuffer::Format + // internal Format stencil bits total bits packed? + gS8 = {GR_GL_STENCIL_INDEX8, 8, 8, false}, + gS16 = {GR_GL_STENCIL_INDEX16, 16, 16, false}, + gD24S8 = {GR_GL_DEPTH24_STENCIL8, 8, 32, true }, + gS4 = {GR_GL_STENCIL_INDEX4, 4, 4, false}, + gS = {GR_GL_STENCIL_INDEX, kUnknownBitCount, kUnknownBitCount, false}, + gDS = {GR_GL_DEPTH_STENCIL, kUnknownBitCount, kUnknownBitCount, true }; + + if (kDesktop_GrGLBinding == this->glBinding()) { + bool supportsPackedDS = fGLVersion >= GR_GL_VER(3,0) || + this->hasExtension("GL_EXT_packed_depth_stencil") || + this->hasExtension("GL_ARB_framebuffer_object"); + + // S1 thru S16 formats are in GL 3.0+, EXT_FBO, and ARB_FBO since we + // require FBO support we can expect these are legal formats and don't + // check. These also all support the unsized GL_STENCIL_INDEX. + fGLCaps.fStencilFormats.push_back() = gS8; + fGLCaps.fStencilFormats.push_back() = gS16; + if (supportsPackedDS) { + fGLCaps.fStencilFormats.push_back() = gD24S8; + } + fGLCaps.fStencilFormats.push_back() = gS4; + if (supportsPackedDS) { + fGLCaps.fStencilFormats.push_back() = gDS; + } + } else { + // ES2 has STENCIL_INDEX8 without extensions. + // ES1 with GL_OES_framebuffer_object (which we require for ES1) + // introduces tokens for S1 thu S8 but there are separate extensions + // that make them legal (GL_OES_stencil1, ...). + // GL_OES_packed_depth_stencil adds DEPTH24_STENCIL8 + // ES doesn't support using the unsized formats. + + if (fGLVersion >= GR_GL_VER(2,0) || + this->hasExtension("GL_OES_stencil8")) { + fGLCaps.fStencilFormats.push_back() = gS8; + } + //fStencilFormats.push_back() = gS16; + if (this->hasExtension("GL_OES_packed_depth_stencil")) { + fGLCaps.fStencilFormats.push_back() = gD24S8; + } + if (this->hasExtension("GL_OES_stencil4")) { + fGLCaps.fStencilFormats.push_back() = gS4; + } + // we require some stencil format. + GrAssert(fGLCaps.fStencilFormats.count() > 0); + } } void GrGpuGL::resetContext() { + if (gPrintStartupSpew && !fPrintedCaps) { + fPrintedCaps = true; + this->getCaps().print(); + fGLCaps.print(); + } + // We detect cases when blending is effectively off fHWBlendDisabled = false; GL_CALL(Enable(GR_GL_BLEND)); @@ -698,66 +712,6 @@ GrResource* GrGpuGL::onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc) } } -/////////////////////////////////////////////////////////////////////////////// - -static const GrGLuint kUnknownBitCount = ~0; - -void GrGpuGL::setupStencilFormats() { - - // Build up list of legal stencil formats (though perhaps not supported on - // the particular gpu/driver) from most preferred to least. - - // these consts are in order of most preferred to least preferred - // we don't bother with GL_STENCIL_INDEX1 or GL_DEPTH32F_STENCIL8 - static const GrGLStencilBuffer::Format - // internal Format stencil bits total bits packed? - gS8 = {GR_GL_STENCIL_INDEX8, 8, 8, false}, - gS16 = {GR_GL_STENCIL_INDEX16, 16, 16, false}, - gD24S8 = {GR_GL_DEPTH24_STENCIL8, 8, 32, true }, - gS4 = {GR_GL_STENCIL_INDEX4, 4, 4, false}, - gS = {GR_GL_STENCIL_INDEX, kUnknownBitCount, kUnknownBitCount, false}, - gDS = {GR_GL_DEPTH_STENCIL, kUnknownBitCount, kUnknownBitCount, true }; - - if (kDesktop_GrGLBinding == this->glBinding()) { - bool supportsPackedDS = fGLVersion >= GR_GL_VER(3,0) || - this->hasExtension("GL_EXT_packed_depth_stencil") || - this->hasExtension("GL_ARB_framebuffer_object"); - - // S1 thru S16 formats are in GL 3.0+, EXT_FBO, and ARB_FBO since we - // require FBO support we can expect these are legal formats and don't - // check. These also all support the unsized GL_STENCIL_INDEX. - fStencilFormats.push_back() = gS8; - fStencilFormats.push_back() = gS16; - if (supportsPackedDS) { - fStencilFormats.push_back() = gD24S8; - } - fStencilFormats.push_back() = gS4; - if (supportsPackedDS) { - fStencilFormats.push_back() = gDS; - } - } else { - // ES2 has STENCIL_INDEX8 without extensions. - // ES1 with GL_OES_framebuffer_object (which we require for ES1) - // introduces tokens for S1 thu S8 but there are separate extensions - // that make them legal (GL_OES_stencil1, ...). - // GL_OES_packed_depth_stencil adds DEPTH24_STENCIL8 - // ES doesn't support using the unsized formats. - - if (fGLVersion >= GR_GL_VER(2,0) || - this->hasExtension("GL_OES_stencil8")) { - fStencilFormats.push_back() = gS8; - } - //fStencilFormats.push_back() = gS16; - if (this->hasExtension("GL_OES_packed_depth_stencil")) { - fStencilFormats.push_back() = gD24S8; - } - if (this->hasExtension("GL_OES_stencil4")) { - fStencilFormats.push_back() = gS4; - } - // we require some stencil format. - GrAssert(fStencilFormats.count() > 0); - } -} //////////////////////////////////////////////////////////////////////////////// @@ -812,7 +766,7 @@ void GrGpuGL::allocateAndUploadTexData(const GrGLTexture::Desc& desc, GL_CALL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, desc.fUploadByteCount)); if (kIndex_8_GrPixelConfig == desc.fFormat && - supports8BitPalette()) { + this->getCaps().f8BitPaletteSupport) { // ES only supports CompressedTexImage2D, not CompressedTexSubimage2D GrAssert(desc.fContentWidth == desc.fAllocWidth); GrAssert(desc.fContentHeight == desc.fAllocHeight); @@ -920,7 +874,7 @@ bool GrGpuGL::createRenderTargetObjects(int width, int height, // If we are using multisampling we will create two FBOS. We render // to one and then resolve to the texture bound to the other. - if (desc->fSampleCnt > 1 && kNone_MSFBO != fMSFBOType) { + if (desc->fSampleCnt > 1 && GLCaps::kNone_MSFBO != fGLCaps.fMSFBOType) { GL_CALL(GenFramebuffers(1, &desc->fRTFBOID)); GL_CALL(GenRenderbuffers(1, &desc->fMSColorRenderbufferID)); if (!desc->fRTFBOID || @@ -1032,39 +986,42 @@ GrTexture* GrGpuGL::onCreateTexture(const GrTextureDesc& desc, return return_null_texture(); } + const Caps& caps = this->getCaps(); + // We keep GrRenderTargets in GL's normal orientation so that they // can be drawn to by the outside world without the client having // to render upside down. glTexDesc.fOrientation = renderTarget ? GrGLTexture::kBottomUp_Orientation : GrGLTexture::kTopDown_Orientation; - GrAssert(as_size_t(desc.fAALevel) < GR_ARRAY_COUNT(fAASamples)); - glRTDesc.fSampleCnt = fAASamples[desc.fAALevel]; - if (kNone_MSFBO == fMSFBOType && desc.fAALevel != kNone_GrAALevel) { + GrAssert(as_size_t(desc.fAALevel) < GR_ARRAY_COUNT(fGLCaps.fAASamples)); + glRTDesc.fSampleCnt = fGLCaps.fAASamples[desc.fAALevel]; + if (GLCaps::kNone_MSFBO == fGLCaps.fMSFBOType && + desc.fAALevel != kNone_GrAALevel) { GrPrintf("AA RT requested but not supported on this platform."); } glTexDesc.fUploadByteCount = GrBytesPerPixel(desc.fFormat); if (renderTarget) { - if (!this->npotRenderTargetSupport()) { + if (!caps.fNPOTRenderTargetSupport) { glTexDesc.fAllocWidth = GrNextPow2(desc.fWidth); glTexDesc.fAllocHeight = GrNextPow2(desc.fHeight); } - glTexDesc.fAllocWidth = GrMax(fMinRenderTargetWidth, + glTexDesc.fAllocWidth = GrMax(caps.fMinRenderTargetWidth, glTexDesc.fAllocWidth); - glTexDesc.fAllocHeight = GrMax(fMinRenderTargetHeight, + glTexDesc.fAllocHeight = GrMax(caps.fMinRenderTargetHeight, glTexDesc.fAllocHeight); - if (glTexDesc.fAllocWidth > fMaxRenderTargetSize || - glTexDesc.fAllocHeight > fMaxRenderTargetSize) { + if (glTexDesc.fAllocWidth > caps.fMaxRenderTargetSize || + glTexDesc.fAllocHeight > caps.fMaxRenderTargetSize) { return return_null_texture(); } - } else if (!this->npotTextureSupport()) { + } else if (!caps.fNPOTTextureSupport) { glTexDesc.fAllocWidth = GrNextPow2(desc.fWidth); glTexDesc.fAllocHeight = GrNextPow2(desc.fHeight); - if (glTexDesc.fAllocWidth > fMaxTextureSize || - glTexDesc.fAllocHeight > fMaxTextureSize) { + if (glTexDesc.fAllocWidth > caps.fMaxTextureSize || + glTexDesc.fAllocHeight > caps.fMaxTextureSize) { return return_null_texture(); } } @@ -1156,13 +1113,14 @@ bool GrGpuGL::createStencilBufferForRenderTarget(GrRenderTarget* rt, GrGLStencilBuffer* sb = NULL; - int stencilFmtCnt = fStencilFormats.count(); + int stencilFmtCnt = fGLCaps.fStencilFormats.count(); for (int i = 0; i < stencilFmtCnt; ++i) { GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, sbID)); // we start with the last stencil format that succeeded in hopes // that we won't go through this loop more than once after the // first (painful) stencil creation. int sIdx = (i + fLastSuccessfulStencilFmtIdx) % stencilFmtCnt; + const GrGLStencilBuffer::Format& sFmt = fGLCaps.fStencilFormats[sIdx]; // 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) { @@ -1170,21 +1128,21 @@ bool GrGpuGL::createStencilBufferForRenderTarget(GrRenderTarget* rt, RenderbufferStorageMultisample( GR_GL_RENDERBUFFER, samples, - fStencilFormats[sIdx].fInternalFormat, + sFmt.fInternalFormat, width, height)); } else { GR_GL_CALL_NOERRCHECK(this->glInterface(), RenderbufferStorage(GR_GL_RENDERBUFFER, - fStencilFormats[sIdx].fInternalFormat, - width, height)); + sFmt.fInternalFormat, + width, height)); } GrGLenum err = GR_GL_GET_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. - GrGLStencilBuffer::Format format = fStencilFormats[sIdx]; + GrGLStencilBuffer::Format format = sFmt; get_stencil_rb_sizes(this->glInterface(), sbID, &format); sb = new GrGLStencilBuffer(this, sbID, width, height, samples, format); @@ -1606,7 +1564,7 @@ void GrGpuGL::onGpuDrawNonIndexed(GrPrimitiveType type, void GrGpuGL::resolveRenderTarget(GrGLRenderTarget* rt) { if (rt->needsResolve()) { - GrAssert(kNone_MSFBO != fMSFBOType); + GrAssert(GLCaps::kNone_MSFBO != fGLCaps.fMSFBOType); GrAssert(rt->textureFBOID() != rt->renderFBOID()); GL_CALL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER, rt->renderFBOID())); @@ -1624,7 +1582,7 @@ void GrGpuGL::resolveRenderTarget(GrGLRenderTarget* rt) { r.setRelativeTo(vp, dirtyRect.fLeft, dirtyRect.fTop, dirtyRect.width(), dirtyRect.height()); - if (kAppleES_MSFBO == fMSFBOType) { + if (GLCaps::kAppleES_MSFBO == fGLCaps.fMSFBOType) { // Apple's extension uses the scissor as the blit bounds. GL_CALL(Enable(GR_GL_SCISSOR_TEST)); GL_CALL(Scissor(r.fLeft, r.fBottom, @@ -1633,10 +1591,10 @@ void GrGpuGL::resolveRenderTarget(GrGLRenderTarget* rt) { fHWBounds.fScissorRect.invalidate(); fHWBounds.fScissorEnabled = true; } else { - if (kDesktopARB_MSFBO != fMSFBOType) { + if (GLCaps::kDesktopARB_MSFBO != fGLCaps.fMSFBOType) { // this respects the scissor during the blit, so disable it. - GrAssert(kDesktopEXT_MSFBO == fMSFBOType); - flushScissor(NULL); + GrAssert(GLCaps::kDesktopEXT_MSFBO == fGLCaps.fMSFBOType); + this->flushScissor(NULL); } int right = r.fLeft + r.fWidth; int top = r.fBottom + r.fHeight; @@ -1716,7 +1674,7 @@ void GrGpuGL::flushStencil() { } else { GL_CALL(Enable(GR_GL_STENCIL_TEST)); #if GR_DEBUG - if (!fStencilWrapOpsSupport) { + if (!this->getCaps().fStencilWrapOpsSupport) { GrAssert(settings->fFrontPassOp != kIncWrap_StencilOp); GrAssert(settings->fFrontPassOp != kDecWrap_StencilOp); GrAssert(settings->fFrontFailOp != kIncWrap_StencilOp); @@ -1768,7 +1726,7 @@ void GrGpuGL::flushStencil() { (unsigned) settings->fBackFailOp < GR_ARRAY_COUNT(grToGLStencilOp)); GrAssert(settings->fBackPassOp >= 0 && (unsigned) settings->fBackPassOp < GR_ARRAY_COUNT(grToGLStencilOp)); - if (fTwoSidedStencilSupport) { + if (this->getCaps().fTwoSidedStencilSupport) { GrGLenum backFunc; unsigned int backRef = settings->fBackFuncRef; @@ -2133,7 +2091,7 @@ bool GrGpuGL::canBeTexture(GrPixelConfig config, *type = GR_GL_UNSIGNED_SHORT_4_4_4_4; break; case kIndex_8_GrPixelConfig: - if (this->supports8BitPalette()) { + if (this->getCaps().f8BitPaletteSupport) { *format = GR_GL_PALETTE8_RGBA8; *internalFormat = GR_GL_PALETTE8_RGBA8; *type = GR_GL_UNSIGNED_BYTE; // unused I think @@ -2177,7 +2135,7 @@ bool GrGpuGL::fboInternalFormat(GrPixelConfig config, GrGLenum* format) { switch (config) { case kRGBA_8888_GrPixelConfig: case kRGBX_8888_GrPixelConfig: - if (fRGBA8Renderbuffer) { + if (fGLCaps.fRGBA8Renderbuffer) { *format = GR_GL_RGBA8; return true; } else { @@ -2267,6 +2225,32 @@ void GrGpuGL::setBuffers(bool indexed, int GrGpuGL::getMaxEdges() const { // FIXME: This is a pessimistic estimate based on how many other things // want to add uniforms. This should be centralized somewhere. - return GR_CT_MIN(fMaxFragmentUniformVectors - 8, kMaxEdges); + return GR_CT_MIN(fGLCaps.fMaxFragmentUniformVectors - 8, kMaxEdges); } +void GrGpuGL::GLCaps::print() const { + for (int i = 0; i < fStencilFormats.count(); ++i) { + GrPrintf("Stencil Format %d, stencil bits: %02d, total bits: %02d\n", + i, + fStencilFormats[i].fStencilBits, + fStencilFormats[i].fTotalBits); + } + + GR_STATIC_ASSERT(0 == kNone_MSFBO); + GR_STATIC_ASSERT(1 == kDesktopARB_MSFBO); + GR_STATIC_ASSERT(2 == kDesktopEXT_MSFBO); + GR_STATIC_ASSERT(3 == kAppleES_MSFBO); + static const char* gMSFBOExtStr[] = { + "None", + "ARB", + "EXT", + "Apple", + }; + GrPrintf("MSAA Type: %s\n", gMSFBOExtStr[fMSFBOType]); + for (int i = 0; i < GR_ARRAY_COUNT(fAASamples); ++i) { + GrPrintf("AA Level %d has %d samples\n", i, fAASamples[i]); + } + GrPrintf("Max FS Uniform Vectors: %d\n", fMaxFragmentUniformVectors); + GrPrintf("Support RGBA8 Render Buffer: %s\n", + (fRGBA8Renderbuffer ? "YES": "NO")); +} diff --git a/gpu/src/GrGpuGL.h b/gpu/src/GrGpuGL.h index a38d6b6f70..353394fd46 100644 --- a/gpu/src/GrGpuGL.h +++ b/gpu/src/GrGpuGL.h @@ -146,9 +146,14 @@ protected: static bool BlendCoeffReferencesConstant(GrBlendCoeff coeff); private: + // Inits GrDrawTarget::Caps and GLCaps, sublcass may enable + // additional caps. + void initCaps(); + + void initFSAASupport(); // determines valid stencil formats - void setupStencilFormats(); + void initStencilFormats(); // notify callbacks to update state tracking when related // objects are bound to GL or deleted outside of the class @@ -194,7 +199,43 @@ private: SkString fExtensionString; GrGLVersion fGLVersion; - SkTArray<GrGLStencilBuffer::Format, true> fStencilFormats; + struct GLCaps { + // prealloc space for 8 stencil formats + GLCaps() : fStencilFormats(8) {} + SkTArray<GrGLStencilBuffer::Format, true> fStencilFormats; + + enum { + /** + * no support for MSAA FBOs + */ + kNone_MSFBO = 0, + /** + * GL3.0-style MSAA FBO (GL_ARB_framebuffer_object) + */ + kDesktopARB_MSFBO, + /** + * earlier GL_EXT_framebuffer* extensions + */ + kDesktopEXT_MSFBO, + /** + * GL_APPLE_framebuffer_multisample ES extension + */ + kAppleES_MSFBO, + } fMSFBOType; + + // TODO: get rid of GrAALevel and use sample cnt directly + GrGLuint fAASamples[4]; + + // The maximum number of fragment uniform vectors (GLES has min. 16). + int fMaxFragmentUniformVectors; + + // ES requires an extension to support RGBA8 in RenderBufferStorage + bool fRGBA8Renderbuffer; + + void print() const; + } fGLCaps; + + // we want to clear stencil buffers when they are created. We want to clear // the entire buffer even if it is larger than the color attachment. We // attach it to this fbo with no color attachment to do the initial clear. @@ -202,23 +243,6 @@ private: bool fHWBlendDisabled; - GrGLuint fAASamples[4]; - enum { - kNone_MSFBO = 0, //<! no support for MSAA FBOs - kDesktopARB_MSFBO,//<! GL3.0-style MSAA FBO (GL_ARB_framebuffer_object) - kDesktopEXT_MSFBO,//<! earlier GL_EXT_framebuffer* extensions - kAppleES_MSFBO, //<! GL_APPLE_framebuffer_multisample ES extension - } fMSFBOType; - - // Do we have stencil wrap ops. - bool fHasStencilWrap; - - // The maximum number of fragment uniform vectors (GLES has min. 16). - int fMaxFragmentUniformVectors; - - // ES requires an extension to support RGBA8 in RenderBufferStorage - bool fRGBA8Renderbuffer; - int fActiveTextureUnitIdx; // we record what stencil format worked last time to hopefully exit early @@ -228,6 +252,8 @@ private: const GrGLInterface* fGL; GrGLBinding fGLBinding; + bool fPrintedCaps; + typedef GrGpu INHERITED; }; diff --git a/gpu/src/GrGpuGLFixed.cpp b/gpu/src/GrGpuGLFixed.cpp index 2c97e69ce2..195ca32502 100644 --- a/gpu/src/GrGpuGLFixed.cpp +++ b/gpu/src/GrGpuGLFixed.cpp @@ -62,9 +62,6 @@ GrGLBinding get_binding_in_use(const GrGLInterface* gl) { GrGpuGLFixed::GrGpuGLFixed(const GrGLInterface* gl) : GrGpuGL(gl, get_binding_in_use(gl)) { - fShaderSupport = false; - fShaderDerivativeSupport = false; - fDualSourceBlendingSupport = false; } GrGpuGLFixed::~GrGpuGLFixed() { diff --git a/gpu/src/GrGpuGLShaders.cpp b/gpu/src/GrGpuGLShaders.cpp index 7d15c4f134..05f6652534 100644 --- a/gpu/src/GrGpuGLShaders.cpp +++ b/gpu/src/GrGpuGLShaders.cpp @@ -213,7 +213,7 @@ bool GrGpuGLShaders::programUnitTest() { bool vertexEdgeAA = random.nextF() > .5f; if (vertexEdgeAA) { pdesc.fVertexLayout |= GrDrawTarget::kEdge_VertexLayoutBit; - if (this->supportsShaderDerivatives()) { + if (this->getCaps().fShaderDerivativeSupport) { pdesc.fVertexEdgeType = random.nextF() > 0.5f ? kHairQuad_EdgeType : kHairLine_EdgeType; @@ -229,7 +229,7 @@ bool GrGpuGLShaders::programUnitTest() { pdesc.fEdgeAANumEdges = 0; } - if (fDualSourceBlendingSupport) { + if (this->getCaps().fDualSourceBlendingSupport) { pdesc.fDualSrcOutput = (ProgramDesc::DualSrcOutput) (int)(random.nextF() * ProgramDesc::kDualSrcOutputCnt); @@ -290,15 +290,15 @@ GrGLBinding get_binding_in_use(const GrGLInterface* gl) { GrGpuGLShaders::GrGpuGLShaders(const GrGLInterface* gl) : GrGpuGL(gl, get_binding_in_use(gl)) { - fShaderSupport = true; + fCaps.fShaderSupport = true; if (kDesktop_GrGLBinding == this->glBinding()) { - fDualSourceBlendingSupport = + fCaps.fDualSourceBlendingSupport = this->glVersion() >= GR_GL_VER(3,3) || this->hasExtension("GL_ARB_blend_func_extended"); - fShaderDerivativeSupport = true; + fCaps.fShaderDerivativeSupport = true; } else { - fDualSourceBlendingSupport = false; - fShaderDerivativeSupport = + fCaps.fDualSourceBlendingSupport = false; + fCaps.fShaderDerivativeSupport = this->hasExtension("GL_OES_standard_derivatives"); } @@ -937,7 +937,7 @@ void GrGpuGLShaders::buildProgram(GrPrimitiveType type) { // (e.g. solid draw, and dst coeff is kZero. It's correct to make // the dst coeff be kISA. Or solid draw with kSA can be tweaked to be // kOne). - if (fDualSourceBlendingSupport) { + if (this->getCaps().fDualSourceBlendingSupport) { if (kZero_BlendCoeff == fCurrDrawState.fDstBlend) { // write the coverage value to second color desc.fDualSrcOutput = ProgramDesc::kCoverage_DualSrcOutput; diff --git a/gpu/src/GrInOrderDrawBuffer.cpp b/gpu/src/GrInOrderDrawBuffer.cpp index 85af430fbf..9519655bfb 100644 --- a/gpu/src/GrInOrderDrawBuffer.cpp +++ b/gpu/src/GrInOrderDrawBuffer.cpp @@ -18,8 +18,7 @@ GrInOrderDrawBuffer::GrInOrderDrawBuffer(const GrGpu* gpu, GrVertexBufferAllocPool* vertexPool, GrIndexBufferAllocPool* indexPool) - : fGpu(gpu) - , fDraws(&fDrawStorage) + : fDraws(&fDrawStorage) , fStates(&fStateStorage) , fClears(&fClearStorage) , fClips(&fClipStorage) @@ -33,12 +32,12 @@ GrInOrderDrawBuffer::GrInOrderDrawBuffer(const GrGpu* gpu, , fVertexPool(*vertexPool) , fIndexPool(*indexPool) , fGeoPoolStateStack(&fGeoStackStorage) { - + + fCaps = gpu->getCaps(); + GrAssert(NULL != vertexPool); GrAssert(NULL != indexPool); - gpu->ref(); - GeometryPoolState& poolState = fGeoPoolStateStack.push_back(); poolState.fUsedPoolVertexBytes = 0; poolState.fUsedPoolIndexBytes = 0; @@ -53,7 +52,6 @@ GrInOrderDrawBuffer::GrInOrderDrawBuffer(const GrGpu* gpu, GrInOrderDrawBuffer::~GrInOrderDrawBuffer() { this->reset(); GrSafeUnref(fQuadIndexBuffer); - fGpu->unref(); } void GrInOrderDrawBuffer::initializeDrawStateAndClip(const GrDrawTarget& target) { @@ -627,7 +625,7 @@ void GrInOrderDrawBuffer::clipWillBeSet(const GrClip& newClip) { } bool GrInOrderDrawBuffer::willUseHWAALines() const { - return fGpu->supportsHWAALines() && + return this->getCaps().fHWAALineSupport && CanUseHWAALines(this->getGeomSrc().fVertexLayout, fCurrDrawState); } diff --git a/gpu/src/GrPathRendererChain.cpp b/gpu/src/GrPathRendererChain.cpp index dc09d43c1e..a6da6d3bd4 100644 --- a/gpu/src/GrPathRendererChain.cpp +++ b/gpu/src/GrPathRendererChain.cpp @@ -57,9 +57,9 @@ GrPathRenderer* GrPathRendererChain::getPathRenderer(const GrDrawTarget* target, void GrPathRendererChain::init() { GrAssert(!fInit); GrGpu* gpu = fOwner->getGpu(); - this->addPathRenderer( - new GrDefaultPathRenderer(gpu->supportsTwoSidedStencil(), - gpu->supportsStencilWrapOps()))->unref(); + bool twoSided = gpu->getCaps().fTwoSidedStencilSupport; + bool wrapOp = gpu->getCaps().fStencilWrapOpsSupport; + this->addPathRenderer(new GrDefaultPathRenderer(twoSided, wrapOp))->unref(); GrPathRenderer::AddPathRenderers(fOwner, fFlags, this); fInit = true; } |