diff options
Diffstat (limited to 'gpu/src')
34 files changed, 2608 insertions, 2393 deletions
diff --git a/gpu/src/GrAtlas.cpp b/gpu/src/GrAtlas.cpp index dfc0a69..e577beb 100644 --- a/gpu/src/GrAtlas.cpp +++ b/gpu/src/GrAtlas.cpp @@ -175,9 +175,9 @@ GrAtlas* GrAtlasMgr::addToAtlas(GrAtlas* atlas, GrAssert(0 == kA8_GrMaskFormat); GrAssert(1 == kA565_GrMaskFormat); if (NULL == fTexture[format]) { - GrGpu::TextureDesc desc = { - GrGpu::kDynamicUpdate_TextureFlag, - GrGpu::kNone_AALevel, + GrTextureDesc desc = { + kDynamicUpdate_GrTextureFlagBit, + kNone_GrAALevel, GR_ATLAS_TEXTURE_WIDTH, GR_ATLAS_TEXTURE_HEIGHT, maskformat2pixelconfig(format) diff --git a/gpu/src/GrBufferAllocPool.cpp b/gpu/src/GrBufferAllocPool.cpp index 0db12fe..d786b02 100644 --- a/gpu/src/GrBufferAllocPool.cpp +++ b/gpu/src/GrBufferAllocPool.cpp @@ -346,8 +346,8 @@ void* GrVertexBufferAllocPool::makeSpace(GrVertexLayout layout, GrAssert(NULL != startVertex); size_t vSize = GrDrawTarget::VertexSize(layout); - size_t offset; - const GrGeometryBuffer* geomBuffer; + size_t offset = 0; // assign to suppress warning + const GrGeometryBuffer* geomBuffer = NULL; // assign to suppress warning void* ptr = INHERITED::makeSpace(vSize * vertexCount, vSize, &geomBuffer, @@ -405,8 +405,8 @@ void* GrIndexBufferAllocPool::makeSpace(int indexCount, GrAssert(NULL != buffer); GrAssert(NULL != startIndex); - size_t offset; - const GrGeometryBuffer* geomBuffer; + size_t offset = 0; // assign to suppress warning + const GrGeometryBuffer* geomBuffer = NULL; // assign to suppress warning void* ptr = INHERITED::makeSpace(indexCount * sizeof(uint16_t), sizeof(uint16_t), &geomBuffer, diff --git a/gpu/src/GrClip.cpp b/gpu/src/GrClip.cpp index e8da3d1..2d1680c 100644 --- a/gpu/src/GrClip.cpp +++ b/gpu/src/GrClip.cpp @@ -18,29 +18,29 @@ #include "GrClip.h" GrClip::GrClip() - : fList(fListMemory, kPreAllocElements) { + : fList(&fListStorage) { fConservativeBounds.setEmpty(); fConservativeBoundsValid = true; } GrClip::GrClip(const GrClip& src) - : fList(fListMemory, kPreAllocElements) { + : fList(&fListStorage) { *this = src; } GrClip::GrClip(const GrIRect& rect) - : fList(fListMemory, kPreAllocElements) { + : fList(&fListStorage) { this->setFromIRect(rect); } GrClip::GrClip(const GrRect& rect) - : fList(fListMemory, kPreAllocElements) { + : fList(&fListStorage) { this->setFromRect(rect); } GrClip::GrClip(GrClipIterator* iter, GrScalar tx, GrScalar ty, const GrRect* bounds) - : fList(fListMemory, kPreAllocElements) { + : fList(&fListStorage) { this->setFromIterator(iter, tx, ty, bounds); } @@ -87,6 +87,12 @@ void GrClip::setFromIRect(const GrIRect& r) { } } +static void intersectWith(SkRect* dst, const SkRect& src) { + if (!dst->intersect(src)) { + dst->setEmpty(); + } +} + void GrClip::setFromIterator(GrClipIterator* iter, GrScalar tx, GrScalar ty, const GrRect* conservativeBounds) { fList.reset(); @@ -118,7 +124,7 @@ void GrClip::setFromIterator(GrClipIterator* iter, GrScalar tx, GrScalar ty, rectCount = 1; fList.pop_back(); GrAssert(kRect_ClipType == fList.back().fType); - fList.back().fRect.intersectWith(e.fRect); + intersectWith(&fList.back().fRect, e.fRect); } } else { isectRectValid = false; diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp index 8017f73..8cb932b 100644 --- a/gpu/src/GrContext.cpp +++ b/gpu/src/GrContext.cpp @@ -15,7 +15,7 @@ */ #include "GrContext.h" -#include "GrTypes.h" +#include "GrGpu.h" #include "GrTextureCache.h" #include "GrTextStrike.h" #include "GrMemory.h" @@ -26,6 +26,8 @@ #include "GrBufferAllocPool.h" #include "GrPathRenderer.h" +#define ENABLE_OFFSCREEN_AA 0 + #define DEFER_TEXT_RENDERING 1 #define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB) @@ -41,8 +43,8 @@ static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4; static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0; static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0; -GrContext* GrContext::Create(GrGpu::Engine engine, - GrGpu::Platform3DContext context3D) { +GrContext* GrContext::Create(GrEngine engine, + GrPlatform3DContext context3D) { GrContext* ctx = NULL; GrGpu* fGpu = GrGpu::Create(engine, context3D); if (NULL != fGpu) { @@ -53,34 +55,43 @@ GrContext* GrContext::Create(GrGpu::Engine engine, } GrContext* GrContext::CreateGLShaderContext() { - return GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, NULL); + return GrContext::Create(kOpenGL_Shaders_GrEngine, NULL); } GrContext::~GrContext() { this->flush(); - fGpu->unref(); delete fTextureCache; delete fFontCache; delete fDrawBuffer; delete fDrawBufferVBAllocPool; delete fDrawBufferIBAllocPool; GrSafeUnref(fCustomPathRenderer); + GrSafeUnref(fAAFillRectIndexBuffer); + GrSafeUnref(fAAStrokeRectIndexBuffer); + fGpu->unref(); } void GrContext::contextLost() { + // abandon first to so destructors + // don't try to free the resources in the API. + fGpu->abandonResources(); + delete fDrawBuffer; fDrawBuffer = NULL; + delete fDrawBufferVBAllocPool; fDrawBufferVBAllocPool = NULL; + delete fDrawBufferIBAllocPool; fDrawBufferIBAllocPool = NULL; + GrSafeSetNull(fAAFillRectIndexBuffer); + GrSafeSetNull(fAAStrokeRectIndexBuffer); + fTextureCache->removeAll(); fFontCache->freeAll(); fGpu->markContextDirty(); - fGpu->abandonResources(); - this->setupDrawBuffer(); } @@ -94,9 +105,45 @@ void GrContext::freeGpuResources() { fFontCache->freeAll(); } +//////////////////////////////////////////////////////////////////////////////// + +enum { + kNPOTBit = 0x1, + kFilterBit = 0x2, + kKeylessBit = 0x4, +}; + +bool GrContext::finalizeTextureKey(GrTextureKey* key, + const GrSamplerState& sampler, + bool keyless) const { + uint32_t bits = 0; + uint16_t width = key->width(); + uint16_t height = key->height(); + + if (!fGpu->npotTextureTileSupport()) { + bool isPow2 = GrIsPow2(width) && GrIsPow2(height); + + bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) || + (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode); + + if (tiled && !isPow2) { + bits |= kNPOTBit; + if (GrSamplerState::kNearest_Filter != sampler.getFilter()) { + bits |= kFilterBit; + } + } + } + + if (keyless) { + bits |= kKeylessBit; + } + key->finalize(bits); + return 0 != bits; +} + GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key, const GrSamplerState& sampler) { - finalizeTextureKey(key, sampler); + finalizeTextureKey(key, sampler, false); return fTextureCache->findAndLock(*key); } @@ -129,7 +176,7 @@ static void stretchImage(void* dst, GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key, const GrSamplerState& sampler, - const GrGpu::TextureDesc& desc, + const GrTextureDesc& desc, void* srcData, size_t rowBytes) { GrAssert(key->width() == desc.fWidth); GrAssert(key->height() == desc.fHeight); @@ -139,7 +186,7 @@ GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key, #endif GrTextureEntry* entry = NULL; - bool special = finalizeTextureKey(key, sampler); + bool special = finalizeTextureKey(key, sampler, false); if (special) { GrTextureEntry* clampEntry; GrTextureKey clampKey(*key); @@ -154,9 +201,10 @@ GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key, return NULL; } } - GrGpu::TextureDesc rtDesc = desc; - rtDesc.fFlags |= GrGpu::kRenderTarget_TextureFlag | - GrGpu::kNoStencil_TextureFlag; + GrTextureDesc rtDesc = desc; + rtDesc.fFlags = rtDesc.fFlags | + kRenderTarget_GrTextureFlagBit | + kNoStencil_GrTextureFlagBit; rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth, fGpu->minRenderTargetWidth())); rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight, @@ -175,9 +223,18 @@ GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key, fGpu->disableState(GrDrawTarget::kDither_StateBit | GrDrawTarget::kClip_StateBit | GrDrawTarget::kAntialias_StateBit); + GrSamplerState::Filter filter; + // if filtering is not desired then we want to ensure all + // texels in the resampled image are copies of texels from + // the original. + if (GrSamplerState::kNearest_Filter == sampler.getFilter()) { + filter = GrSamplerState::kNearest_Filter; + } else { + filter = GrSamplerState::kBilinear_Filter; + } GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode, GrSamplerState::kClamp_WrapMode, - sampler.isFilter()); + filter); fGpu->setSamplerState(0, stretchSampler); static const GrVertexLayout layout = @@ -202,7 +259,7 @@ GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key, // not. Either implement filtered stretch blit on CPU or just create // one when FBO case fails. - rtDesc.fFlags = 0; + rtDesc.fFlags = kNone_GrTextureFlags; // no longer need to clamp at min RT size. rtDesc.fWidth = GrNextPow2(desc.fWidth); rtDesc.fHeight = GrNextPow2(desc.fHeight); @@ -234,19 +291,37 @@ GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key, return entry; } -void GrContext::unlockTexture(GrTextureEntry* entry) { - fTextureCache->unlock(entry); -} - -void GrContext::detachCachedTexture(GrTextureEntry* entry) { - fTextureCache->detach(entry); +GrTextureEntry* GrContext::lockKeylessTexture(const GrTextureDesc& desc) { + uint32_t p0 = desc.fFormat; + uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags; + GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight); + this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(), true); + + GrTextureEntry* entry = fTextureCache->findAndLock(key); + if (NULL == entry) { + GrTexture* texture = fGpu->createTexture(desc, NULL, 0); + if (NULL != texture) { + entry = fTextureCache->createAndLock(key, texture); + } + } + // If the caller gives us the same desc/sampler twice we don't want + // to return the same texture the second time (unless it was previously + // released). So we detach the entry from the cache and reattach at release. + if (NULL != entry) { + fTextureCache->detach(entry); + } + return entry; } -void GrContext::reattachAndUnlockCachedTexture(GrTextureEntry* entry) { - fTextureCache->reattachAndUnlock(entry); +void GrContext::unlockTexture(GrTextureEntry* entry) { + if (kKeylessBit & entry->key().getPrivateBits()) { + fTextureCache->reattachAndUnlock(entry); + } else { + fTextureCache->unlock(entry); + } } -GrTexture* GrContext::createUncachedTexture(const GrGpu::TextureDesc& desc, +GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc, void* srcData, size_t rowBytes) { return fGpu->createTexture(desc, srcData, rowBytes); @@ -285,6 +360,25 @@ GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) return fGpu->createPlatformSurface(desc); } +GrRenderTarget* GrContext::createPlatformRenderTarget(intptr_t platformRenderTarget, + int stencilBits, + bool isMultisampled, + int width, int height) { +#if GR_DEBUG + GrPrintf("Using deprecated createPlatformRenderTarget API."); +#endif + return fGpu->createPlatformRenderTarget(platformRenderTarget, + stencilBits, isMultisampled, + width, height); +} + +GrRenderTarget* GrContext::createRenderTargetFrom3DApiState() { +#if GR_DEBUG + GrPrintf("Using deprecated createRenderTargetFrom3DApiState API."); +#endif + return fGpu->createRenderTargetFrom3DApiState(); +} + /////////////////////////////////////////////////////////////////////////////// bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler, @@ -312,6 +406,8 @@ bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler, //////////////////////////////////////////////////////////////////////////////// +const GrClip& GrContext::getClip() const { return fGpu->getClip(); } + void GrContext::setClip(const GrClip& clip) { fGpu->setClip(clip); fGpu->enableState(GrDrawTarget::kClip_StateBit); @@ -325,8 +421,9 @@ void GrContext::setClip(const GrIRect& rect) { //////////////////////////////////////////////////////////////////////////////// -void GrContext::eraseColor(GrColor color) { - fGpu->eraseColor(color); +void GrContext::clear(const GrIRect* rect, const GrColor color) { + this->flush(); + fGpu->clear(rect, color); } void GrContext::drawPaint(const GrPaint& paint) { @@ -345,14 +442,212 @@ void GrContext::drawPaint(const GrPaint& paint) { this->drawRect(paint, r); } +//////////////////////////////////////////////////////////////////////////////// + +bool GrContext::doOffscreenAA(GrDrawTarget* target, + const GrPaint& paint, + bool isLines) const { +#if !ENABLE_OFFSCREEN_AA + return false; +#else + if (!paint.fAntiAlias) { + return false; + } + if (isLines && fGpu->supportsAALines()) { + return false; + } + if (target->getRenderTarget()->isMultisampled()) { + return false; + } + // we have to be sure that the blend equation is expressible + // as simple src / dst coeffecients when the source + // is already modulated by the coverage fraction. + // We could use dual-source blending to get the correct per-pixel + // dst coeffecient for the remaining cases. + if (kISC_BlendCoeff != paint.fDstBlendCoeff && + kOne_BlendCoeff != paint.fDstBlendCoeff && + kISA_BlendCoeff != paint.fDstBlendCoeff) { + return false; + } + return true; +#endif +} + +bool GrContext::setupOffscreenAAPass1(GrDrawTarget* target, + bool requireStencil, + const GrIRect& boundRect, + OffscreenRecord* record) { + GrAssert(ENABLE_OFFSCREEN_AA); + + GrAssert(NULL == record->fEntry0); + GrAssert(NULL == record->fEntry1); + + int boundW = boundRect.width(); + int boundH = boundRect.height(); + int size = GrMax(64, (int)GrNextPow2(GrMax(boundW, boundH))); + + GrTextureDesc desc; + if (requireStencil) { + desc.fFlags = kRenderTarget_GrTextureFlagBit; + } else { + desc.fFlags = kRenderTarget_GrTextureFlagBit | + kNoStencil_GrTextureFlagBit; + } + + desc.fFormat = kRGBA_8888_GrPixelConfig; + + int scale; + // Using MSAA seems to be slower for some yet unknown reason. + if (false && fGpu->supportsFullsceneAA()) { + record->fDownsample = OffscreenRecord::kFSAA_Downsample; + scale = GR_Scalar1; + desc.fAALevel = kMed_GrAALevel; + } else { + record->fDownsample = (fGpu->supports4x4DownsampleFilter()) ? + OffscreenRecord::k4x4SinglePass_Downsample : + OffscreenRecord::k4x4TwoPass_Downsample; + scale = 4; + desc.fAALevel = kNone_GrAALevel; + } + + desc.fWidth = scale * size; + desc.fHeight = scale * size; + + record->fEntry0 = this->lockKeylessTexture(desc); + + if (NULL == record->fEntry0) { + return false; + } + + if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) { + desc.fWidth /= 2; + desc.fHeight /= 2; + record->fEntry1 = this->lockKeylessTexture(desc); + if (NULL == record->fEntry1) { + this->unlockTexture(record->fEntry0); + record->fEntry0 = NULL; + return false; + } + } + + GrRenderTarget* offRT0 = record->fEntry0->texture()->asRenderTarget(); + GrAssert(NULL != offRT0); + + target->saveCurrentDrawState(&record->fSavedState); + + GrPaint tempPaint; + tempPaint.reset(); + SetPaint(tempPaint, target); + target->setRenderTarget(offRT0); + + GrMatrix transM; + transM.setTranslate(-boundRect.fLeft, -boundRect.fTop); + target->postConcatViewMatrix(transM); + GrMatrix scaleM; + scaleM.setScale(scale * GR_Scalar1, scale * GR_Scalar1); + target->postConcatViewMatrix(scaleM); + + // clip gets applied in second pass + target->disableState(GrDrawTarget::kClip_StateBit); + + GrIRect clear = SkIRect::MakeWH(scale * boundW, scale * boundH); + target->clear(&clear, 0x0); + + return true; +} + +void GrContext::offscreenAAPass2(GrDrawTarget* target, + const GrPaint& paint, + const GrIRect& boundRect, + OffscreenRecord* record) { + + GrAssert(NULL != record->fEntry0); + + GrSamplerState::Filter filter; + if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) { + filter = GrSamplerState::k4x4Downsample_Filter; + } else { + filter = GrSamplerState::kBilinear_Filter; + } + + GrMatrix sampleM; + GrSamplerState sampler(GrSamplerState::kClamp_WrapMode, + GrSamplerState::kClamp_WrapMode, filter); + + GrTexture* src = record->fEntry0->texture(); + int scale; + + if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) { + GrAssert(NULL != record->fEntry1); + scale = 2; + GrRenderTarget* dst = record->fEntry1->texture()->asRenderTarget(); + + // Do 2x2 downsample from first to second + target->setTexture(kOffscreenStage, src); + target->setRenderTarget(dst); + target->setViewMatrix(GrMatrix::I()); + sampleM.setScale(scale * GR_Scalar1 / src->width(), + scale * GR_Scalar1 / src->height()); + sampler.setMatrix(sampleM); + target->setSamplerState(kOffscreenStage, sampler); + GrRect rect = SkRect::MakeWH(scale * boundRect.width(), + scale * boundRect.height()); + target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage); + + src = record->fEntry1->texture(); + } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) { + scale = 1; + GrIRect rect = SkIRect::MakeWH(boundRect.width(), boundRect.height()); + src->asRenderTarget()->overrideResolveRect(rect); + } else { + GrAssert(OffscreenRecord::k4x4SinglePass_Downsample == + record->fDownsample); + scale = 4; + } + + // setup for draw back to main RT + target->restoreDrawState(record->fSavedState); + if (NULL != paint.getTexture()) { + GrMatrix invVM; + if (target->getViewInverse(&invVM)) { + target->preConcatSamplerMatrix(0, invVM); + } + } + target->setViewMatrix(GrMatrix::I()); + + target->setTexture(kOffscreenStage, src); + sampleM.setScale(scale * GR_Scalar1 / src->width(), + scale * GR_Scalar1 / src->height()); + sampler.setMatrix(sampleM); + sampleM.setTranslate(-boundRect.fLeft, -boundRect.fTop); + sampler.preConcatMatrix(sampleM); + target->setSamplerState(kOffscreenStage, sampler); + + GrRect dstRect; + int stages = (1 << kOffscreenStage) | (NULL == paint.getTexture() ? 0 : 1); + dstRect.set(boundRect); + target->drawSimpleRect(dstRect, NULL, stages); + + this->unlockTexture(record->fEntry0); + record->fEntry0 = NULL; + if (NULL != record->fEntry1) { + this->unlockTexture(record->fEntry1); + record->fEntry1 = NULL; + } + target->restoreDrawState(record->fSavedState); +} + +//////////////////////////////////////////////////////////////////////////////// + /* create a triangle strip that strokes the specified triangle. There are 8 unique vertices, but we repreat the last 2 to close up. Alternatively we could use an indices array, and then only send 8 verts, but not sure that would be faster. */ -static void setStrokeRectStrip(GrPoint verts[10], const GrRect& rect, +static void setStrokeRectStrip(GrPoint verts[10], GrRect rect, GrScalar width) { const GrScalar rad = GrScalarHalf(width); + rect.sort(); verts[0].set(rect.fLeft + rad, rect.fTop + rad); verts[1].set(rect.fLeft - rad, rect.fTop - rad); @@ -366,6 +661,243 @@ static void setStrokeRectStrip(GrPoint verts[10], const GrRect& rect, verts[9] = verts[1]; } +static GrColor getColorForMesh(const GrPaint& paint) { + if (NULL == paint.getTexture()) { + return paint.fColor; + } else { + unsigned a = GrColorUnpackA(paint.fColor); + return GrColorPackRGBA(a, a, a, a); + } +} + +static void setInsetFan(GrPoint* pts, size_t stride, + const GrRect& r, GrScalar dx, GrScalar dy) { + pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride); +} + +static const uint16_t gFillAARectIdx[] = { + 0, 1, 5, 5, 4, 0, + 1, 2, 6, 6, 5, 1, + 2, 3, 7, 7, 6, 2, + 3, 0, 4, 4, 7, 3, + 4, 5, 6, 6, 7, 4, +}; + +int GrContext::aaFillRectIndexCount() const { + return GR_ARRAY_COUNT(gFillAARectIdx); +} + +GrIndexBuffer* GrContext::aaFillRectIndexBuffer() { + if (NULL == fAAFillRectIndexBuffer) { + fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx), + false); + GrAssert(NULL != fAAFillRectIndexBuffer); +#if GR_DEBUG + bool updated = +#endif + fAAFillRectIndexBuffer->updateData(gFillAARectIdx, + sizeof(gFillAARectIdx)); + GR_DEBUGASSERT(updated); + } + return fAAFillRectIndexBuffer; +} + +static const uint16_t gStrokeAARectIdx[] = { + 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0, + 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0, + 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0, + 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0, + + 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4, + 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4, + 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4, + 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4, + + 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8, + 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8, + 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8, + 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8, +}; + +int GrContext::aaStrokeRectIndexCount() const { + return GR_ARRAY_COUNT(gStrokeAARectIdx); +} + +GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() { + if (NULL == fAAStrokeRectIndexBuffer) { + fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx), + false); + GrAssert(NULL != fAAStrokeRectIndexBuffer); +#if GR_DEBUG + bool updated = +#endif + fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx, + sizeof(gStrokeAARectIdx)); + GR_DEBUGASSERT(updated); + } + return fAAStrokeRectIndexBuffer; +} + +void GrContext::fillAARect(GrDrawTarget* target, + const GrPaint& paint, + const GrRect& devRect) { + + GrVertexLayout layout = GrDrawTarget::kColor_VertexLayoutBit; + if (NULL != paint.getTexture()) { + layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0); + } + + size_t vsize = GrDrawTarget::VertexSize(layout); + + GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0); + + intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices()); + + GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts); + GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize); + + setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf); + setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf); + + verts += sizeof(GrPoint); + for (int i = 0; i < 4; ++i) { + *reinterpret_cast<GrColor*>(verts + i * vsize) = 0; + } + + GrColor innerColor = getColorForMesh(paint); + verts += 4 * vsize; + for (int i = 0; i < 4; ++i) { + *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor; + } + + target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer()); + + target->drawIndexed(kTriangles_PrimitiveType, 0, + 0, 8, this->aaFillRectIndexCount()); +} + +void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint, + const GrRect& devRect, const GrVec& devStrokeSize) { + const GrScalar& dx = devStrokeSize.fX; + const GrScalar& dy = devStrokeSize.fY; + const GrScalar rx = GrMul(dx, GR_ScalarHalf); + const GrScalar ry = GrMul(dy, GR_ScalarHalf); + + GrVertexLayout layout = GrDrawTarget::kColor_VertexLayoutBit; + + if (NULL != paint.getTexture()) { + layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0); + } + + GrScalar spare; + { + GrScalar w = devRect.width() - dx; + GrScalar h = devRect.height() - dy; + spare = GrMin(w, h); + } + + if (spare <= 0) { + GrRect r(devRect); + r.inset(-rx, -ry); + fillAARect(target, paint, r); + return; + } + + size_t vsize = GrDrawTarget::VertexSize(layout); + + GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0); + + intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices()); + + GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts); + GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize); + GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize); + GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize); + + setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf); + setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf); + setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf); + setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf); + + verts += sizeof(GrPoint); + for (int i = 0; i < 4; ++i) { + *reinterpret_cast<GrColor*>(verts + i * vsize) = 0; + } + + GrColor innerColor = getColorForMesh(paint); + verts += 4 * vsize; + for (int i = 0; i < 8; ++i) { + *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor; + } + + verts += 8 * vsize; + for (int i = 0; i < 8; ++i) { + *reinterpret_cast<GrColor*>(verts + i * vsize) = 0; + } + + target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer()); + target->drawIndexed(kTriangles_PrimitiveType, + 0, 0, 16, aaStrokeRectIndexCount()); +} + +/** + * Returns true if the rects edges are integer-aligned. + */ +static bool isIRect(const GrRect& r) { + return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) && + GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom); +} + +static bool apply_aa_to_rect(GrDrawTarget* target, + GrGpu* gpu, + const GrPaint& paint, + const GrRect& rect, + GrScalar width, + const GrMatrix* matrix, + GrMatrix* combinedMatrix, + GrRect* devRect) { + // we use a simple alpha ramp to do aa on axis-aligned rects + // do AA with alpha ramp if the caller requested AA, the rect + // will be axis-aligned,the render target is not + // multisampled, and the rect won't land on integer coords. + + if (!paint.fAntiAlias) { + return false; + } + + if (target->getRenderTarget()->isMultisampled()) { + return false; + } + + if (0 == width && gpu->supportsAALines()) { + return false; + } + + if (!target->getViewMatrix().preservesAxisAlignment()) { + return false; + } + + if (NULL != matrix && + !matrix->preservesAxisAlignment()) { + return false; + } + + *combinedMatrix = target->getViewMatrix(); + if (NULL != matrix) { + combinedMatrix->preConcat(*matrix); + GrAssert(combinedMatrix->preservesAxisAlignment()); + } + + combinedMatrix->mapRect(devRect, rect); + devRect->sort(); + + if (width < 0) { + return !isIRect(*devRect); + } else { + return true; + } +} + void GrContext::drawRect(const GrPaint& paint, const GrRect& rect, GrScalar width, @@ -375,13 +907,43 @@ void GrContext::drawRect(const GrPaint& paint, GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory); + GrRect devRect = rect; + GrMatrix combinedMatrix; + bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix, + &combinedMatrix, &devRect); + + if (doAA) { + GrDrawTarget::AutoViewMatrixRestore avm(target); + if (textured) { + GrMatrix inv; + if (combinedMatrix.invert(&inv)) { + target->preConcatSamplerMatrix(0, inv); + } + } + target->setViewMatrix(GrMatrix::I()); + if (width >= 0) { + GrVec strokeSize;; + if (width > 0) { + strokeSize.set(width, width); + combinedMatrix.mapVectors(&strokeSize, 1); + strokeSize.setAbs(strokeSize); + } else { + strokeSize.set(GR_Scalar1, GR_Scalar1); + } + strokeAARect(target, paint, devRect, strokeSize); + } else { + fillAARect(target, paint, devRect); + } + return; + } + if (width >= 0) { // TODO: consider making static vertex buffers for these cases. // Hairline could be done by just adding closing vertex to // unitSquareVertexBuffer() - GrVertexLayout layout = (textured) ? - GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) : - 0; + GrVertexLayout layout = textured ? + GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) : + 0; static const int worstCaseVertCount = 10; GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0); @@ -412,7 +974,9 @@ void GrContext::drawRect(const GrPaint& paint, if (NULL != matrix) { avmr.set(target); target->preConcatViewMatrix(*matrix); - target->preConcatSamplerMatrix(0, *matrix); + if (textured) { + target->preConcatSamplerMatrix(0, *matrix); + } } target->drawNonIndexed(primType, 0, vertCount); @@ -425,9 +989,9 @@ void GrContext::drawRect(const GrPaint& paint, fGpu->getUnitSquareVertexBuffer()); GrDrawTarget::AutoViewMatrixRestore avmr(target); GrMatrix m; - m.setAll(rect.width(), 0, rect.fLeft, - 0, rect.height(), rect.fTop, - 0, 0, GrMatrix::I()[8]); + m.setAll(rect.width(), 0, rect.fLeft, + 0, rect.height(), rect.fTop, + 0, 0, GrMatrix::I()[8]); if (NULL != matrix) { m.postConcat(*matrix); @@ -531,6 +1095,10 @@ void GrContext::drawVertices(const GrPaint& paint, vertexSize += sizeof(GrColor); } + bool doAA = false; + OffscreenRecord record; + GrIRect bounds; + if (sizeof(GrPoint) != vertexSize) { if (!geo.set(target, layout, vertexCount, 0)) { GrPrintf("Failed to get space for vertices!"); @@ -555,33 +1123,84 @@ void GrContext::drawVertices(const GrPaint& paint, curVertex = (void*)((intptr_t)curVertex + vsize); } } else { + // we don't do offscreen AA when we have per-vertex tex coords or colors + if (this->doOffscreenAA(target, paint, GrIsPrimTypeLines(primitiveType))) { + GrRect b; + b.setBounds(positions, vertexCount); + target->getViewMatrix().mapRect(&b); + b.roundOut(&bounds); + + if (this->setupOffscreenAAPass1(target, false, bounds, &record)) { + doAA = true; + } + } target->setVertexSourceToArray(layout, positions, vertexCount); } if (NULL != indices) { target->setIndexSourceToArray(indices, indexCount); + } + + if (NULL != indices) { target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount); } else { target->drawNonIndexed(primitiveType, 0, vertexCount); } + + if (doAA) { + this->offscreenAAPass2(target, paint, bounds, &record); + } } -//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// void GrContext::drawPath(const GrPaint& paint, GrPathIter* path, GrPathFill fill, const GrPoint* translate) { - GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory); + GrPathRenderer* pr = this->getPathRenderer(target, path, fill); + + if (!IsFillInverted(fill) && // will be relaxed soon + !pr->supportsAA(target, path, fill) && + this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) { + + OffscreenRecord record; + bool needsStencil = pr->requiresStencilPass(target, path, fill); + + // compute bounds as intersection of rt size, clip, and path + GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(), + target->getRenderTarget()->height()); + if (target->getClip().hasConservativeBounds()) { + GrIRect clipIBounds; + target->getClip().getConservativeBounds().roundOut(&clipIBounds); + if (!bound.intersect(clipIBounds)) { + return; + } + } + GrRect pathBounds; + if (path->getConservativeBounds(&pathBounds)) { + GrIRect pathIBounds; + target->getViewMatrix().mapRect(&pathBounds, pathBounds); + pathBounds.roundOut(&pathIBounds); + if (!bound.intersect(pathIBounds)) { + return; + } + } + if (this->setupOffscreenAAPass1(target, needsStencil, bound, &record)) { + pr->drawPath(target, 0, path, fill, translate); + this->offscreenAAPass2(target, paint, bound, &record); + return; + } + } GrDrawTarget::StageBitfield enabledStages = 0; if (NULL != paint.getTexture()) { enabledStages |= 1; } - GrPathRenderer* pr = getPathRenderer(target, path, fill); + pr->drawPath(target, enabledStages, path, fill, translate); } @@ -659,8 +1278,8 @@ void GrContext::writePixels(int left, int top, int width, int height, // TODO: when underlying api has a direct way to do this we should use it // (e.g. glDrawPixels on desktop GL). - const GrGpu::TextureDesc desc = { - 0, GrGpu::kNone_AALevel, width, height, config + const GrTextureDesc desc = { + kNone_GrTextureFlags, kNone_GrAALevel, width, height, config }; GrTexture* texture = fGpu->createTexture(desc, buffer, stride); if (NULL == texture) { @@ -716,6 +1335,7 @@ void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) { target->disableState(GrDrawTarget::kAntialias_StateBit); } target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff); + target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode); } GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint, @@ -787,7 +1407,7 @@ void GrContext::resetStats() { fGpu->resetStats(); } -const GrGpu::Stats& GrContext::getStats() const { +const GrGpuStats& GrContext::getStats() const { return fGpu->getStats(); } @@ -816,6 +1436,9 @@ GrContext::GrContext(GrGpu* gpu) : fDrawBufferVBAllocPool = NULL; fDrawBufferIBAllocPool = NULL; + fAAFillRectIndexBuffer = NULL; + fAAStrokeRectIndexBuffer = NULL; + this->setupDrawBuffer(); } @@ -844,28 +1467,6 @@ void GrContext::setupDrawBuffer() { #endif } -bool GrContext::finalizeTextureKey(GrTextureKey* key, - const GrSamplerState& sampler) const { - uint32_t bits = 0; - uint16_t width = key->width(); - uint16_t height = key->height(); - - - if (!fGpu->npotTextureTileSupport()) { - bool isPow2 = GrIsPow2(width) && GrIsPow2(height); - - bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) || - (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode); - - if (tiled && !isPow2) { - bits |= 1; - bits |= sampler.isFilter() ? 2 : 0; - } - } - key->finalize(bits); - return 0 != bits; -} - GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) { GrDrawTarget* target; #if DEFER_TEXT_RENDERING @@ -892,3 +1493,4 @@ GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target, return &fDefaultPathRenderer; } } + diff --git a/gpu/src/GrDrawTarget.cpp b/gpu/src/GrDrawTarget.cpp index 1413c6d..518b4ee 100644 --- a/gpu/src/GrDrawTarget.cpp +++ b/gpu/src/GrDrawTarget.cpp @@ -22,7 +22,7 @@ // recursive helper for creating mask with all the tex coord bits set for // one stage template <int N> -static int stage_mask_recur(int stage) { +int stage_mask_recur(int stage) { return GrDrawTarget::StageTexCoordVertexLayoutBit(stage, N) | stage_mask_recur<N+1>(stage); } @@ -43,7 +43,7 @@ static int stage_mask(int stage) { // recursive helper for creating mask of with all bits set relevant to one // texture coordinate index template <int N> -static int tex_coord_mask_recur(int texCoordIdx) { +int tex_coord_mask_recur(int texCoordIdx) { return GrDrawTarget::StageTexCoordVertexLayoutBit(N, texCoordIdx) | tex_coord_mask_recur<N+1>(texCoordIdx); } @@ -335,6 +335,10 @@ void GrDrawTarget::preConcatViewMatrix(const GrMatrix& matrix) { fCurrDrawState.fViewMatrix.preConcat(matrix); } +void GrDrawTarget::postConcatViewMatrix(const GrMatrix& matrix) { + fCurrDrawState.fViewMatrix.postConcat(matrix); +} + const GrMatrix& GrDrawTarget::getViewMatrix() const { return fCurrDrawState.fViewMatrix; } @@ -376,6 +380,11 @@ void GrDrawTarget::setColor(GrColor c) { fCurrDrawState.fColor = c; } +void GrDrawTarget::setColorFilter(GrColor c, SkXfermode::Mode mode) { + fCurrDrawState.fColorFilterColor = c; + fCurrDrawState.fColorFilterXfermode = mode; +} + void GrDrawTarget::setAlpha(uint8_t a) { this->setColor((a << 24) | (a << 16) | (a << 8) | a); } @@ -409,9 +418,13 @@ bool GrDrawTarget::reserveAndLockGeometry(GrVertexLayout vertexLayout, if (vertexCount) { fGeometrySrc.fVertexSrc = kReserved_GeometrySrcType; fGeometrySrc.fVertexLayout = vertexLayout; + } else if (NULL != vertices) { + *vertices = NULL; } if (indexCount) { fGeometrySrc.fIndexSrc = kReserved_GeometrySrcType; + } else if (NULL != indices) { + *indices = NULL; } } return fReservedGeometry.fLocked; @@ -465,6 +478,11 @@ void GrDrawTarget::setIndexSourceToBuffer(const GrIndexBuffer* buffer) { /////////////////////////////////////////////////////////////////////////////// bool GrDrawTarget::canDisableBlend() const { + // If we're using edge antialiasing, we can't force blend off. + if (fCurrDrawState.fFlagBits & kEdgeAA_StateBit) { + return false; + } + if ((kOne_BlendCoeff == fCurrDrawState.fSrcBlend) && (kZero_BlendCoeff == fCurrDrawState.fDstBlend)) { return true; @@ -490,20 +508,34 @@ bool GrDrawTarget::canDisableBlend() const { // ...and there isn't a texture with an alpha channel... for (int s = 0; s < kNumStages; ++s) { - if (VertexUsesStage(s, fGeometrySrc.fVertexLayout)) { + if (this->isStageEnabled(s)) { GrAssert(NULL != fCurrDrawState.fTextures[s]); + GrPixelConfig config = fCurrDrawState.fTextures[s]->config(); - if (kRGB_565_GrPixelConfig != config && - kRGBX_8888_GrPixelConfig != config) { + if (!GrPixelConfigIsOpaque(config)) { return false; } } } + // ...and there isn't an interesting color filter... + // TODO: Consider being more aggressive with regards to disabling + // blending when a color filter is used. + if (SkXfermode::kDst_Mode != fCurrDrawState.fColorFilterXfermode) { + return false; + } + // ...then we disable blend. return true; } + +/////////////////////////////////////////////////////////////////////////////// +void GrDrawTarget::setEdgeAAData(const float edges[18]) { + memcpy(fCurrDrawState.fEdgeAAEdges, edges, sizeof(fCurrDrawState.fEdgeAAEdges)); +} + + /////////////////////////////////////////////////////////////////////////////// void GrDrawTarget::drawRect(const GrRect& rect, const GrMatrix* matrix, @@ -581,6 +613,9 @@ void GrDrawTarget::SetRectVertices(const GrRect& rect, } /////////////////////////////////////////////////////////////////////////////// +GrDrawTarget::AutoStateRestore::AutoStateRestore() { + fDrawTarget = NULL; +} GrDrawTarget::AutoStateRestore::AutoStateRestore(GrDrawTarget* target) { fDrawTarget = target; @@ -595,3 +630,14 @@ GrDrawTarget::AutoStateRestore::~AutoStateRestore() { } } +void GrDrawTarget::AutoStateRestore::set(GrDrawTarget* target) { + if (target != fDrawTarget) { + if (NULL != fDrawTarget) { + fDrawTarget->restoreDrawState(fDrawState); + } + if (NULL != target) { + fDrawTarget->saveCurrentDrawState(&fDrawState); + } + fDrawTarget = target; + } +} diff --git a/gpu/src/GrGLEffect.h b/gpu/src/GrGLEffect.h index 7c85b6d..ef00df8 100644 --- a/gpu/src/GrGLEffect.h +++ b/gpu/src/GrGLEffect.h @@ -23,12 +23,12 @@ class GrEffect; struct ShaderCodeSegments { - GrSStringBuilder<256> fVSUnis; - GrSStringBuilder<256> fVSAttrs; - GrSStringBuilder<256> fVaryings; - GrSStringBuilder<256> fFSUnis; - GrSStringBuilder<512> fVSCode; - GrSStringBuilder<512> fFSCode; + GrStringBuilder fVSUnis; + GrStringBuilder fVSAttrs; + GrStringBuilder fVaryings; + GrStringBuilder fFSUnis; + GrStringBuilder fVSCode; + GrStringBuilder fFSCode; }; /** diff --git a/gpu/src/GrGLInterface.cpp b/gpu/src/GrGLInterface.cpp index 5dfc03c..0825a3f 100644 --- a/gpu/src/GrGLInterface.cpp +++ b/gpu/src/GrGLInterface.cpp @@ -93,3 +93,246 @@ void gl_version(int* major, int* minor) { GrGLGetGLInterface()->fGetString(GR_GL_VERSION)); gl_version_from_string(major, minor, v); } + +bool GrGLInterface::validateShaderFunctions() const { + // required for GrGpuGLShaders + if (NULL == fAttachShader || + NULL == fBindAttribLocation || + NULL == fCompileShader || + NULL == fCreateProgram || + NULL == fCreateShader || + NULL == fDeleteProgram || + NULL == fDeleteShader || + NULL == fDisableVertexAttribArray || + NULL == fEnableVertexAttribArray || + NULL == fGetProgramInfoLog || + NULL == fGetProgramiv || + NULL == fGetShaderInfoLog || + NULL == fGetShaderiv || + NULL == fGetUniformLocation || + NULL == fLinkProgram || + NULL == fShaderSource || + NULL == fUniform1f || + NULL == fUniform1i || + NULL == fUniform1fv || + NULL == fUniform1iv || + NULL == fUniform2f || + NULL == fUniform2i || + NULL == fUniform2fv || + NULL == fUniform2iv || + NULL == fUniform3f || + NULL == fUniform3i || + NULL == fUniform3fv || + NULL == fUniform3iv || + NULL == fUniform4f || + NULL == fUniform4i || + NULL == fUniform4fv || + NULL == fUniform4iv || + NULL == fUniformMatrix2fv || + NULL == fUniformMatrix3fv || + NULL == fUniformMatrix4fv || + NULL == fUseProgram || + NULL == fVertexAttrib4fv || + NULL == fVertexAttribPointer) { + return false; + } + return true; +} + +bool GrGLInterface::validateFixedFunctions() const { + if (NULL == fClientActiveTexture || + NULL == fColor4ub || + NULL == fColorPointer || + NULL == fDisableClientState || + NULL == fEnableClientState || + NULL == fLoadMatrixf || + NULL == fMatrixMode || + NULL == fPointSize || + NULL == fShadeModel || + NULL == fTexCoordPointer || + NULL == fTexEnvi || + NULL == fVertexPointer) { + return false; + } + return true; +} + +bool GrGLInterface::validate(GrEngine engine) const { + + bool isDesktop = kDesktop_GrGLBinding == fBindingsExported; + + // ES1 and 2 can be supported in the same interface + bool isES = ((kES1_GrGLBinding | kES2_GrGLBinding) & fBindingsExported && + !(~(kES1_GrGLBinding | kES2_GrGLBinding) & fBindingsExported)); + + if (!isDesktop && !isES) { + return false; + } + + // functions that are always required + if (NULL == fActiveTexture || + NULL == fBindBuffer || + NULL == fBindTexture || + NULL == fBlendFunc || + NULL == fBufferData || + NULL == fBufferSubData || + NULL == fClear || + NULL == fClearColor || + NULL == fClearStencil || + NULL == fColorMask || + NULL == fCullFace || + NULL == fDeleteBuffers || + NULL == fDeleteTextures || + NULL == fDepthMask || + NULL == fDisable || + NULL == fDrawArrays || + NULL == fDrawElements || + NULL == fEnable || + NULL == fFrontFace || + NULL == fGenBuffers || + NULL == fGenTextures || + NULL == fGetBufferParameteriv || + NULL == fGetError || + NULL == fGetIntegerv || + NULL == fGetString || + NULL == fPixelStorei || + NULL == fReadPixels || + NULL == fScissor || + NULL == fStencilFunc || + NULL == fStencilMask || + NULL == fStencilOp || + NULL == fTexImage2D || + NULL == fTexParameteri || + NULL == fTexSubImage2D || + NULL == fViewport || + NULL == fBindFramebuffer || + NULL == fBindRenderbuffer || + NULL == fCheckFramebufferStatus || + NULL == fDeleteFramebuffers || + NULL == fDeleteRenderbuffers || + NULL == fFramebufferRenderbuffer || + NULL == fFramebufferTexture2D || + NULL == fGenFramebuffers || + NULL == fGenRenderbuffers || + NULL == fRenderbufferStorage) { + return false; + } + + switch (engine) { + case kOpenGL_Shaders_GrEngine: + if (kES1_GrGLBinding == fBindingsExported) { + return false; + } + if (!this->validateShaderFunctions()) { + return false; + } + break; + case kOpenGL_Fixed_GrEngine: + if (kES1_GrGLBinding == fBindingsExported) { + return false; + } + if (!this->validateFixedFunctions()) { + return false; + } + break; + default: + return false; + } + + int major, minor; + const char* ext; + + gl_version(&major, &minor); + ext = (const char*)fGetString(GR_GL_EXTENSIONS); + + // Now check that baseline ES/Desktop fns not covered above are present + // and that we have fn pointers for any advertised extensions that we will + // try to use. + + // these functions are part of ES2, we assume they are available + // On the desktop we assume they are available if the extension + // is present or GL version is high enough. + if ((kES2_GrGLBinding & fBindingsExported)) { + if (NULL == fBlendColor || + NULL == fStencilFuncSeparate || + NULL == fStencilMaskSeparate || + NULL == fStencilOpSeparate) { + return false; + } + } else if (kDesktop_GrGLBinding == fBindingsExported) { + if (major >= 2) { + if (NULL == fStencilFuncSeparate || + NULL == fStencilMaskSeparate || + NULL == fStencilOpSeparate) { + return false; + } + } + if (1 < major || (1 == major && 4 <= minor) || + has_gl_extension_from_string("GL_EXT_blend_color", ext)) { + if (NULL == fBlendColor) { + return false; + } + } + } + + // optional function on desktop before 1.3 + if (kDesktop_GrGLBinding != fBindingsExported || + (1 < major || (1 == major && 3 <= minor)) || + has_gl_extension_from_string("GL_ARB_texture_compression", ext)) { + if (NULL == fCompressedTexImage2D) { + return false; + } + } + + // part of desktop GL + if (kDesktop_GrGLBinding == fBindingsExported && + NULL == fLineWidth) { + return false; + } + // FBO MSAA + if (kDesktop_GrGLBinding == fBindingsExported) { + // GL 3.0 and the ARB extension have multisample + blit + if ((major >= 3) || has_gl_extension_from_string("GL_ARB_framebuffer_object", ext)) { + if (NULL == fRenderbufferStorageMultisample || + NULL == fBlitFramebuffer) { + return false; + } + } else { + if (has_gl_extension_from_string("GL_EXT_framebuffer_blit", ext) && + NULL == fBlitFramebuffer) { + return false; + } + if (has_gl_extension_from_string("GL_EXT_framebuffer_multisample", ext) && + NULL == fRenderbufferStorageMultisample) { + return false; + } + } + } else { + if (has_gl_extension_from_string("GL_CHROMIUM_framebuffer_multisample", ext)) { + if (NULL == fRenderbufferStorageMultisample || + NULL == fBlitFramebuffer) { + return false; + } + } + if (has_gl_extension_from_string("GL_APPLE_framebuffer_multisample", ext)) { + if (NULL == fRenderbufferStorageMultisample || + NULL == fResolveMultisampleFramebuffer) { + return false; + } + } + } + + // On ES buffer mapping is an extension. On Desktop + // buffer mapping was part of original VBO extension + // which we require. + if (kDesktop_GrGLBinding == fBindingsExported || + has_gl_extension_from_string("GL_OES_mapbuffer", ext)) { + if (NULL == fMapBuffer || + NULL == fUnmapBuffer) { + return false; + } + } + + return true; +} + diff --git a/gpu/src/GrGLProgram.cpp b/gpu/src/GrGLProgram.cpp index 5dd09f0..5d2d8b3 100644 --- a/gpu/src/GrGLProgram.cpp +++ b/gpu/src/GrGLProgram.cpp @@ -20,7 +20,8 @@ #include "GrGLConfig.h" #include "GrGLEffect.h" #include "GrMemory.h" -#include "GrStringBuilder.h" + +#include "SkXfermode.h" namespace { @@ -28,7 +29,7 @@ const char* GrPrecision() { if (GR_GL_SUPPORT_ES2) { return "mediump"; } else { - return ""; + return " "; } } @@ -42,7 +43,9 @@ const char* GrShaderPrecision() { } // namespace -#if ATTRIBUTE_MATRIX +#define PRINT_SHADERS 0 + +#if GR_GL_ATTRIBUTE_MATRICES #define VIEW_MATRIX_NAME "aViewM" #else #define VIEW_MATRIX_NAME "uViewM" @@ -50,13 +53,13 @@ const char* GrShaderPrecision() { #define POS_ATTR_NAME "aPosition" #define COL_ATTR_NAME "aColor" - -// for variable names etc -typedef GrSStringBuilder<16> GrTokenString; +#define COL_UNI_NAME "uColor" +#define EDGES_UNI_NAME "uEdges" +#define COL_FILTER_UNI_NAME "uColorFilter" static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) { *s = "aTexCoord"; - s->appendInt(coordIdx); + s->appendS32(coordIdx); } static inline const char* float_vector_type(int count) { @@ -84,32 +87,37 @@ static inline const char* vector_all_coords(int count) { } static void tex_matrix_name(int stage, GrStringBuilder* s) { -#if ATTRIBUTE_MATRIX +#if GR_GL_ATTRIBUTE_MATRICES *s = "aTexM"; #else *s = "uTexM"; #endif - s->appendInt(stage); + s->appendS32(stage); +} + +static void normalized_texel_size_name(int stage, GrStringBuilder* s) { + *s = "uTexelSize"; + s->appendS32(stage); } static void sampler_name(int stage, GrStringBuilder* s) { *s = "uSampler"; - s->appendInt(stage); + s->appendS32(stage); } static void stage_varying_name(int stage, GrStringBuilder* s) { *s = "vStage"; - s->appendInt(stage); + s->appendS32(stage); } static void radial2_param_name(int stage, GrStringBuilder* s) { *s = "uRadial2Params"; - s->appendInt(stage); + s->appendS32(stage); } static void radial2_varying_name(int stage, GrStringBuilder* s) { *s = "vB"; - s->appendInt(stage); + s->appendS32(stage); } GrGLProgram::GrGLProgram() { @@ -119,7 +127,6 @@ GrGLProgram::GrGLProgram() { } GrGLProgram::~GrGLProgram() { - } void GrGLProgram::buildKey(GrBinHashKeyBuilder& key) const { @@ -171,156 +178,272 @@ void GrGLProgram::doGLPost() const { } } -void GrGLProgram::genProgram(GrGLProgram::CachedData* programData, - const GrDrawTarget* target) const { +/** + * Create a text coefficient to be used in fragment shader code. + */ +static void coefficientString(GrStringBuilder* str, SkXfermode::Coeff coeff, + const char* src, const char* dst) { + switch (coeff) { + case SkXfermode::kZero_Coeff: /** 0 */ + *str = "0.0"; + break; + case SkXfermode::kOne_Coeff: /** 1 */ + *str = "1.0"; + break; + case SkXfermode::kSA_Coeff: /** src alpha */ + str->appendf("%s.a", src); + break; + case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */ + str->appendf("(1.0 - %s.a)", src); + break; + case SkXfermode::kDA_Coeff: /** dst alpha */ + str->appendf("%s.a", dst); + break; + case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */ + str->appendf("(1.0 - %s.a)", dst); + break; + case SkXfermode::kSC_Coeff: + str->append(src); + break; + default: + break; + } +} + +/** + * Adds a line to the fragment shader code which modifies the color by + * the specified color filter. + */ +static void addColorFilter(GrStringBuilder* FSCode, const char * outputVar, + SkXfermode::Mode colorFilterXfermode, const char* dstColor) { + SkXfermode::Coeff srcCoeff, dstCoeff; + SkDEBUGCODE(bool success =) + SkXfermode::ModeAsCoeff(colorFilterXfermode, &srcCoeff, &dstCoeff); + // We currently do not handle modes that cannot be represented as + // coefficients. + GrAssert(success); + GrStringBuilder srcCoeffStr, dstCoeffStr; + coefficientString(&srcCoeffStr, srcCoeff, COL_FILTER_UNI_NAME, dstColor); + coefficientString(&dstCoeffStr, dstCoeff, COL_FILTER_UNI_NAME, dstColor); + FSCode->appendf("\t%s = %s*%s + %s*%s;\n", outputVar, srcCoeffStr.c_str(), + COL_FILTER_UNI_NAME, dstCoeffStr.c_str(), dstColor); +} + +bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const { ShaderCodeSegments segments; const uint32_t& layout = fProgramDesc.fVertexLayout; - memset(&programData->fUniLocations, 0, sizeof(UniLocations)); + programData->fUniLocations.reset(); - bool haveColor = !(ProgramDesc::kVertexColorAllOnes_OptFlagBit & - fProgramDesc.fOptFlags); - -#if ATTRIBUTE_MATRIX - segments.fVSAttrs = "attribute mat3 " VIEW_MATRIX_NAME ";\n"; +#if GR_GL_ATTRIBUTE_MATRICES + segments.fVSAttrs += "attribute mat3 " VIEW_MATRIX_NAME ";\n"; + programData->fUniLocations.fViewMatrixUni = kSetAsAttribute; #else - segments.fVSUnis = "uniform mat3 " VIEW_MATRIX_NAME ";\n"; - segments.fVSAttrs = ""; + segments.fVSUnis += "uniform mat3 " VIEW_MATRIX_NAME ";\n"; + programData->fUniLocations.fViewMatrixUni = kUseUniform; #endif segments.fVSAttrs += "attribute vec2 " POS_ATTR_NAME ";\n"; - if (haveColor) { - segments.fVSAttrs += "attribute vec4 " COL_ATTR_NAME ";\n"; - segments.fVaryings = "varying vec4 vColor;\n"; - } else { - segments.fVaryings = ""; + + segments.fVSCode.append( + "void main() {\n" + "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3("POS_ATTR_NAME", 1);\n" + "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n"); + + // incoming color to current stage being processed. + GrStringBuilder inColor; + + switch (fProgramDesc.fColorType) { + case ProgramDesc::kAttribute_ColorType: + segments.fVSAttrs.append( "attribute vec4 " COL_ATTR_NAME ";\n"); + segments.fVaryings.append("varying vec4 vColor;\n"); + segments.fVSCode.append( "\tvColor = " COL_ATTR_NAME ";\n"); + inColor = "vColor"; + break; + case ProgramDesc::kUniform_ColorType: + segments.fFSUnis.append( "uniform vec4 " COL_UNI_NAME ";\n"); + programData->fUniLocations.fColorUni = kUseUniform; + inColor = COL_UNI_NAME; + break; + case ProgramDesc::kNone_ColorType: + inColor = ""; + break; } - segments.fVSCode = "void main() {\n" - "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3(" POS_ATTR_NAME ", 1);\n" - "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n"; - if (haveColor) { - segments.fVSCode += "\tvColor = " COL_ATTR_NAME ";\n"; + if (fProgramDesc.fUsesEdgeAA) { + segments.fFSUnis.append("uniform vec3 " EDGES_UNI_NAME "[6];\n"); } - if (!(fProgramDesc.fOptFlags & ProgramDesc::kNotPoints_OptFlagBit)) { - segments.fVSCode += "\tgl_PointSize = 1.0;\n"; + if (fProgramDesc.fEmitsPointSize){ + segments.fVSCode.append("\tgl_PointSize = 1.0;\n"); } - segments.fFSCode = "void main() {\n"; + + segments.fFSCode.append("void main() {\n"); // add texture coordinates that are used to the list of vertex attr decls - GrTokenString texCoordAttrs[GrDrawTarget::kMaxTexCoords]; + GrStringBuilder texCoordAttrs[GrDrawTarget::kMaxTexCoords]; for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) { - if (target->VertexUsesTexCoordIdx(t, layout)) { + if (GrDrawTarget::VertexUsesTexCoordIdx(t, layout)) { tex_attr_name(t, texCoordAttrs + t); - - segments.fVSAttrs += "attribute vec2 "; - segments.fVSAttrs += texCoordAttrs[t]; - segments.fVSAttrs += ";\n"; + segments.fVSAttrs.appendf("attribute vec2 %s;\n", texCoordAttrs[t].c_str()); } } + bool useColorFilter = + // The rest of transfer mode color filters have not been implemented + fProgramDesc.fColorFilterXfermode <= SkXfermode::kMultiply_Mode + // This mode has no effect. + && fProgramDesc.fColorFilterXfermode != SkXfermode::kDst_Mode; + bool onlyUseColorFilter = useColorFilter + && (fProgramDesc.fColorFilterXfermode == SkXfermode::kClear_Mode + || fProgramDesc.fColorFilterXfermode == SkXfermode::kSrc_Mode); + if (useColorFilter) { + // Set up a uniform for the color + segments.fFSUnis.append( "uniform vec4 " COL_FILTER_UNI_NAME ";\n"); + programData->fUniLocations.fColorFilterUni = kUseUniform; + } + // for each enabled stage figure out what the input coordinates are // and count the number of stages in use. const char* stageInCoords[GrDrawTarget::kNumStages]; int numActiveStages = 0; - for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { - if (fProgramDesc.fStages[s].fEnabled) { - if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) { - stageInCoords[s] = POS_ATTR_NAME; - } else { - int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout); - // we better have input tex coordinates if stage is enabled. - GrAssert(tcIdx >= 0); - GrAssert(texCoordAttrs[tcIdx].length()); - stageInCoords[s] = texCoordAttrs[tcIdx].cstr(); + if (!onlyUseColorFilter) { + for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { + if (fProgramDesc.fStages[s].fEnabled) { + if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) { + stageInCoords[s] = POS_ATTR_NAME; + } else { + int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout); + // we better have input tex coordinates if stage is enabled. + GrAssert(tcIdx >= 0); + GrAssert(texCoordAttrs[tcIdx].size()); + stageInCoords[s] = texCoordAttrs[tcIdx].c_str(); + } + ++numActiveStages; } - ++numActiveStages; } } - GrTokenString inColor = "vColor"; - // if we have active stages string them together, feeding the output color // of each to the next and generating code for each stage. if (numActiveStages) { int currActiveStage = 0; + GrStringBuilder outColor; for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { if (fProgramDesc.fStages[s].fEnabled) { - GrTokenString outColor; - if (currActiveStage < (numActiveStages - 1)) { + if (currActiveStage < (numActiveStages - 1) || useColorFilter) { outColor = "color"; - outColor.appendInt(currActiveStage); - segments.fFSCode += "\tvec4 "; - segments.fFSCode += outColor; - segments.fFSCode += ";\n"; + outColor.appendS32(currActiveStage); + segments.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str()); } else { outColor = "gl_FragColor"; } genStageCode(s, fProgramDesc.fStages[s], - haveColor ? inColor.cstr() : NULL, - outColor.cstr(), + inColor.size() ? inColor.c_str() : NULL, + outColor.c_str(), stageInCoords[s], &segments, &programData->fUniLocations.fStages[s]); ++currActiveStage; inColor = outColor; - haveColor = true; } } + if (useColorFilter) { + addColorFilter(&segments.fFSCode, "gl_FragColor", + fProgramDesc.fColorFilterXfermode, outColor.c_str()); + } + } else { - segments.fFSCode += "\tgl_FragColor = "; - if (haveColor) { - segments.fFSCode += inColor; + if (fProgramDesc.fUsesEdgeAA) { + // FIXME: put the a's in a loop + segments.fFSCode.append( + "\tvec3 pos = vec3(gl_FragCoord.xy, 1);\n" + "\tfloat a0 = clamp(dot(uEdges[0], pos), 0.0, 1.0);\n" + "\tfloat a1 = clamp(dot(uEdges[1], pos), 0.0, 1.0);\n" + "\tfloat a2 = clamp(dot(uEdges[2], pos), 0.0, 1.0);\n" + "\tfloat a3 = clamp(dot(uEdges[3], pos), 0.0, 1.0);\n" + "\tfloat a4 = clamp(dot(uEdges[4], pos), 0.0, 1.0);\n" + "\tfloat a5 = clamp(dot(uEdges[5], pos), 0.0, 1.0);\n" + "\tfloat edgeAlpha = min(min(a0 * a1, a2 * a3), a4 * a5);\n"); + if (inColor.size()) { + inColor.append(" * edgeAlpha"); + } else { + inColor = "vec4(edgeAlpha)"; + } + } + // we may not have any incoming color + const char * incomingColor = (inColor.size() ? inColor.c_str() + : "vec4(1,1,1,1)"); + if (useColorFilter) { + addColorFilter(&segments.fFSCode, "gl_FragColor", + fProgramDesc.fColorFilterXfermode, incomingColor); } else { - segments.fFSCode += "vec4(1,1,1,1)"; + segments.fFSCode.appendf("\tgl_FragColor = %s;\n", incomingColor); } - segments.fFSCode += ";\n"; } - segments.fFSCode += "}\n"; - segments.fVSCode += "}\n"; + segments.fVSCode.append("}\n"); + segments.fFSCode.append("}\n"); + + if (!CompileFSAndVS(segments, programData)) { + return false; + } + + if (!this->bindAttribsAndLinkProgram(texCoordAttrs, programData)) { + return false; + } + + this->getUniformLocationsAndInitCache(programData); + + return true; +} +bool GrGLProgram::CompileFSAndVS(const ShaderCodeSegments& segments, + CachedData* programData) { const char* strings[4]; int lengths[4]; int stringCnt = 0; - if (segments.fVSUnis.length()) { - strings[stringCnt] = segments.fVSUnis.cstr(); - lengths[stringCnt] = segments.fVSUnis.length(); + if (segments.fVSUnis.size()) { + strings[stringCnt] = segments.fVSUnis.c_str(); + lengths[stringCnt] = segments.fVSUnis.size(); ++stringCnt; } - if (segments.fVSAttrs.length()) { - strings[stringCnt] = segments.fVSAttrs.cstr(); - lengths[stringCnt] = segments.fVSAttrs.length(); + if (segments.fVSAttrs.size()) { + strings[stringCnt] = segments.fVSAttrs.c_str(); + lengths[stringCnt] = segments.fVSAttrs.size(); ++stringCnt; } - if (segments.fVaryings.length()) { - strings[stringCnt] = segments.fVaryings.cstr(); - lengths[stringCnt] = segments.fVaryings.length(); + if (segments.fVaryings.size()) { + strings[stringCnt] = segments.fVaryings.c_str(); + lengths[stringCnt] = segments.fVaryings.size(); ++stringCnt; } - GrAssert(segments.fVSCode.length()); - strings[stringCnt] = segments.fVSCode.cstr(); - lengths[stringCnt] = segments.fVSCode.length(); + GrAssert(segments.fVSCode.size()); + strings[stringCnt] = segments.fVSCode.c_str(); + lengths[stringCnt] = segments.fVSCode.size(); ++stringCnt; #if PRINT_SHADERS - GrPrintf("%s%s%s%s\n", - segments.fVSUnis.cstr(), - segments.fVSAttrs.cstr(), - segments.fVaryings.cstr(), - segments.fVSCode.cstr()); + GrPrintf(segments.fVSUnis.c_str()); + GrPrintf(segments.fVSAttrs.c_str()); + GrPrintf(segments.fVaryings.c_str()); + GrPrintf(segments.fVSCode.c_str()); + GrPrintf("\n"); #endif programData->fVShaderID = CompileShader(GR_GL_VERTEX_SHADER, stringCnt, strings, lengths); + if (!programData->fVShaderID) { + return false; + } + stringCnt = 0; if (strlen(GrShaderPrecision()) > 1) { @@ -328,73 +451,117 @@ void GrGLProgram::genProgram(GrGLProgram::CachedData* programData, lengths[stringCnt] = strlen(GrShaderPrecision()); ++stringCnt; } - if (segments.fFSUnis.length()) { - strings[stringCnt] = segments.fFSUnis.cstr(); - lengths[stringCnt] = segments.fFSUnis.length(); + if (segments.fFSUnis.size()) { + strings[stringCnt] = segments.fFSUnis.c_str(); + lengths[stringCnt] = segments.fFSUnis.size(); ++stringCnt; } - if (segments.fVaryings.length()) { - strings[stringCnt] = segments.fVaryings.cstr(); - lengths[stringCnt] = segments.fVaryings.length(); + if (segments.fVaryings.size()) { + strings[stringCnt] = segments.fVaryings.c_str(); + lengths[stringCnt] = segments.fVaryings.size(); ++stringCnt; } - GrAssert(segments.fFSCode.length()); - strings[stringCnt] = segments.fFSCode.cstr(); - lengths[stringCnt] = segments.fFSCode.length(); + GrAssert(segments.fFSCode.size()); + strings[stringCnt] = segments.fFSCode.c_str(); + lengths[stringCnt] = segments.fFSCode.size(); ++stringCnt; #if PRINT_SHADERS - GrPrintf("%s%s%s%s\n", - GR_SHADER_PRECISION, - segments.fFSUnis.cstr(), - segments.fVaryings.cstr(), - segments.fFSCode.cstr()); + GrPrintf(GrShaderPrecision()); + GrPrintf(segments.fFSUnis.c_str()); + GrPrintf(segments.fVaryings.c_str()); + GrPrintf(segments.fFSCode.c_str()); + GrPrintf("\n"); #endif programData->fFShaderID = CompileShader(GR_GL_FRAGMENT_SHADER, stringCnt, strings, lengths); + if (!programData->fFShaderID) { + return false; + } + return true; +} + +GrGLuint GrGLProgram::CompileShader(GrGLenum type, + int stringCnt, + const char** strings, + int* stringLengths) { + GrGLuint shader = GR_GL(CreateShader(type)); + if (0 == shader) { + return 0; + } + + GrGLint compiled = GR_GL_INIT_ZERO; + GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths)); + GR_GL(CompileShader(shader)); + GR_GL(GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled)); + + if (!compiled) { + GrGLint infoLen = GR_GL_INIT_ZERO; + GR_GL(GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen)); + GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger + if (infoLen > 0) { + GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get())); + for (int i = 0; i < stringCnt; ++i) { + if (NULL == stringLengths || stringLengths[i] < 0) { + GrPrintf(strings[i]); + } else { + GrPrintf("%.*s", stringLengths[i], strings[i]); + } + } + GrPrintf("\n%s", log.get()); + } + GrAssert(!"Shader compilation failed!"); + GR_GL(DeleteShader(shader)); + return 0; + } + return shader; +} + +bool GrGLProgram::bindAttribsAndLinkProgram(GrStringBuilder texCoordAttrNames[], + CachedData* programData) const { programData->fProgramID = GR_GL(CreateProgram()); + if (!programData->fProgramID) { + return false; + } const GrGLint& progID = programData->fProgramID; GR_GL(AttachShader(progID, programData->fVShaderID)); GR_GL(AttachShader(progID, programData->fFShaderID)); // Bind the attrib locations to same values for all shaders - GR_GL(BindAttribLocation(progID, POS_ATTR_LOCATION, POS_ATTR_NAME)); + GR_GL(BindAttribLocation(progID, PositionAttributeIdx(), POS_ATTR_NAME)); for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) { - if (texCoordAttrs[t].length()) { + if (texCoordAttrNames[t].size()) { GR_GL(BindAttribLocation(progID, - TEX_ATTR_LOCATION(t), - texCoordAttrs[t].cstr())); + TexCoordAttributeIdx(t), + texCoordAttrNames[t].c_str())); } } -#if ATTRIBUTE_MATRIX - // set unis to a bogus value so that checks against -1 before - // flushing will pass. - GR_GL(BindAttribLocation(progID, - VIEWMAT_ATTR_LOCATION, - VIEW_MATRIX_NAME)); - program->fUniLocations.fViewMatrixUni = BOGUS_MATRIX_UNI_LOCATION; + if (kSetAsAttribute == programData->fUniLocations.fViewMatrixUni) { + GR_GL(BindAttribLocation(progID, + ViewMatrixAttributeIdx(), + VIEW_MATRIX_NAME)); + } - for (int s = 0; s < kNumStages; ++s) { - if (fProgramDesc.fStages[s].fEnabled) { + for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { + const StageUniLocations& unis = programData->fUniLocations.fStages[s]; + if (kSetAsAttribute == unis.fTextureMatrixUni) { GrStringBuilder matName; tex_matrix_name(s, &matName); GR_GL(BindAttribLocation(progID, - TEXMAT_ATTR_LOCATION(s), - matName.cstr())); - program->fUniLocations.fStages[s].fTextureMatrixUni = - BOGUS_MATRIX_UNI_LOCATION; + TextureMatrixAttributeIdx(s), + matName.c_str())); } } -#endif - GR_GL(BindAttribLocation(progID, COL_ATTR_LOCATION, COL_ATTR_NAME)); + + GR_GL(BindAttribLocation(progID, ColorAttributeIdx(), COL_ATTR_NAME)); GR_GL(LinkProgram(progID)); @@ -414,107 +581,93 @@ void GrGLProgram::genProgram(GrGLProgram::CachedData* programData, GrAssert(!"Error linking program"); GR_GL(DeleteProgram(progID)); programData->fProgramID = 0; - return; + return false; + } + return true; +} + +void GrGLProgram::getUniformLocationsAndInitCache(CachedData* programData) const { + const GrGLint& progID = programData->fProgramID; + + if (kUseUniform == programData->fUniLocations.fViewMatrixUni) { + programData->fUniLocations.fViewMatrixUni = + GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME)); + GrAssert(kUnusedUniform != programData->fUniLocations.fViewMatrixUni); + } + if (kUseUniform == programData->fUniLocations.fColorUni) { + programData->fUniLocations.fColorUni = + GR_GL(GetUniformLocation(progID, COL_UNI_NAME)); + GrAssert(kUnusedUniform != programData->fUniLocations.fColorUni); + } + if (kUseUniform == programData->fUniLocations.fColorFilterUni) { + programData->fUniLocations.fColorFilterUni = + GR_GL(GetUniformLocation(progID, COL_FILTER_UNI_NAME)); + GrAssert(kUnusedUniform != programData->fUniLocations.fColorFilterUni); + } + + if (fProgramDesc.fUsesEdgeAA) { + programData->fUniLocations.fEdgesUni = + GR_GL(GetUniformLocation(progID, EDGES_UNI_NAME)); + GrAssert(kUnusedUniform != programData->fUniLocations.fEdgesUni); + } else { + programData->fUniLocations.fEdgesUni = kUnusedUniform; } - // Get uniform locations -#if !ATTRIBUTE_MATRIX - programData->fUniLocations.fViewMatrixUni = - GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME)); - GrAssert(-1 != programData->fUniLocations.fViewMatrixUni); -#endif for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { StageUniLocations& locations = programData->fUniLocations.fStages[s]; if (fProgramDesc.fStages[s].fEnabled) { -#if !ATTRIBUTE_MATRIX - if (locations.fTextureMatrixUni) { - GrTokenString texMName; + if (kUseUniform == locations.fTextureMatrixUni) { + GrStringBuilder texMName; tex_matrix_name(s, &texMName); locations.fTextureMatrixUni = GR_GL(GetUniformLocation( progID, - texMName.cstr())); - GrAssert(-1 != locations.fTextureMatrixUni); - } else { - locations.fTextureMatrixUni = -1; - + texMName.c_str())); + GrAssert(kUnusedUniform != locations.fTextureMatrixUni); } -#endif - if (locations.fSamplerUni) { - GrTokenString samplerName; + if (kUseUniform == locations.fSamplerUni) { + GrStringBuilder samplerName; sampler_name(s, &samplerName); locations.fSamplerUni = GR_GL(GetUniformLocation( progID, - samplerName.cstr())); - GrAssert(-1 != locations.fSamplerUni); - } else { - locations.fSamplerUni = -1; + samplerName.c_str())); + GrAssert(kUnusedUniform != locations.fSamplerUni); + } + + if (kUseUniform == locations.fNormalizedTexelSizeUni) { + GrStringBuilder texelSizeName; + normalized_texel_size_name(s, &texelSizeName); + locations.fNormalizedTexelSizeUni = + GR_GL(GetUniformLocation(progID, texelSizeName.c_str())); + GrAssert(kUnusedUniform != locations.fNormalizedTexelSizeUni); } - if (locations.fRadial2Uni) { - GrTokenString radial2ParamName; + if (kUseUniform == locations.fRadial2Uni) { + GrStringBuilder radial2ParamName; radial2_param_name(s, &radial2ParamName); locations.fRadial2Uni = GR_GL(GetUniformLocation( progID, - radial2ParamName.cstr())); - GrAssert(-1 != locations.fRadial2Uni); - } else { - locations.fRadial2Uni = -1; + radial2ParamName.c_str())); + GrAssert(kUnusedUniform != locations.fRadial2Uni); } - } else { - locations.fSamplerUni = -1; - locations.fRadial2Uni = -1; - locations.fTextureMatrixUni = -1; } } GR_GL(UseProgram(progID)); // init sampler unis and set bogus values for state tracking for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { - if (-1 != programData->fUniLocations.fStages[s].fSamplerUni) { + if (kUnusedUniform != programData->fUniLocations.fStages[s].fSamplerUni) { GR_GL(Uniform1i(programData->fUniLocations.fStages[s].fSamplerUni, s)); } programData->fTextureMatrices[s] = GrMatrix::InvalidMatrix(); programData->fRadial2CenterX1[s] = GR_ScalarMax; programData->fRadial2Radius0[s] = -GR_ScalarMax; + programData->fTextureWidth[s] = -1; + programData->fTextureHeight[s] = -1; } programData->fViewMatrix = GrMatrix::InvalidMatrix(); -} - -GrGLuint GrGLProgram::CompileShader(GrGLenum type, - int stringCnt, - const char** strings, - int* stringLengths) { - GrGLuint shader = GR_GL(CreateShader(type)); - if (0 == shader) { - return 0; - } - - GrGLint compiled = GR_GL_INIT_ZERO; - GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths)); - GR_GL(CompileShader(shader)); - GR_GL(GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled)); - - if (!compiled) { - GrGLint infoLen = GR_GL_INIT_ZERO; - GR_GL(GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen)); - GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger - if (infoLen > 0) { - GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get())); - for (int i = 0; i < stringCnt; ++i) { - if (NULL == stringLengths || stringLengths[i] < 0) { - GrPrintf(strings[i]); - } else { - GrPrintf("%.*s", stringLengths[i], strings[i]); - } - } - GrPrintf("\n%s", log.get()); - } - GrAssert(!"Shader compilation failed!"); - GR_GL(DeleteShader(shader)); - return 0; - } - return shader; + programData->fColor = GrColor_ILLEGAL; + programData->fColorFilterColor = GrColor_ILLEGAL; } //============================================================================ @@ -522,16 +675,16 @@ GrGLuint GrGLProgram::CompileShader(GrGLenum type, //============================================================================ void GrGLProgram::genStageCode(int stageNum, - const GrGLProgram::ProgramDesc::StageDesc& desc, - const char* fsInColor, // NULL means no incoming color - const char* fsOutColor, - const char* vsInCoord, - ShaderCodeSegments* segments, - StageUniLocations* locations) const { + const GrGLProgram::ProgramDesc::StageDesc& desc, + const char* fsInColor, // NULL means no incoming color + const char* fsOutColor, + const char* vsInCoord, + ShaderCodeSegments* segments, + StageUniLocations* locations) const { GrAssert(stageNum >= 0 && stageNum <= 9); - GrTokenString varyingName; + GrStringBuilder varyingName; stage_varying_name(stageNum, &varyingName); // First decide how many coords are needed to access the texture @@ -543,20 +696,17 @@ void GrGLProgram::genStageCode(int stageNum, // decide whether we need a matrix to transform texture coords // and whether the varying needs a perspective coord. - GrTokenString texMName; + GrStringBuilder texMName; tex_matrix_name(stageNum, &texMName); if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) { varyingDims = coordDims; } else { - #if ATTRIBUTE_MATRIX - segments->fVSAttrs += "attribute mat3 "; - segments->fVSAttrs += texMName; - segments->fVSAttrs += ";\n"; + #if GR_GL_ATTRIBUTE_MATRICES + segments->fVSAttrs.appendf("attribute mat3 %s;\n", texMName.c_str()); + locations->fTextureMatrixUni = kSetAsAttribute; #else - segments->fVSUnis += "uniform mat3 "; - segments->fVSUnis += texMName; - segments->fVSUnis += ";\n"; - locations->fTextureMatrixUni = 1; + segments->fVSUnis.appendf("uniform mat3 %s;\n", texMName.c_str()); + locations->fTextureMatrixUni = kUseUniform; #endif if (desc.fOptFlags & ProgramDesc::StageDesc::kNoPerspective_OptFlagBit) { varyingDims = coordDims; @@ -565,217 +715,182 @@ void GrGLProgram::genStageCode(int stageNum, } } - GrTokenString samplerName; + GrStringBuilder samplerName; sampler_name(stageNum, &samplerName); - segments->fFSUnis += "uniform sampler2D "; - segments->fFSUnis += samplerName; - segments->fFSUnis += ";\n"; - locations->fSamplerUni = 1; + segments->fFSUnis.appendf("uniform sampler2D %s;\n", samplerName.c_str()); + locations->fSamplerUni = kUseUniform; + + GrStringBuilder texelSizeName; + if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) { + normalized_texel_size_name(stageNum, &texelSizeName); + segments->fFSUnis.appendf("uniform vec2 %s;\n", texelSizeName.c_str()); + } - segments->fVaryings += "varying "; - segments->fVaryings += float_vector_type(varyingDims); - segments->fVaryings += " "; - segments->fVaryings += varyingName; - segments->fVaryings += ";\n"; + segments->fVaryings.appendf("varying %s %s;\n", + float_vector_type(varyingDims), varyingName.c_str()); if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) { GrAssert(varyingDims == coordDims); - segments->fVSCode += "\t"; - segments->fVSCode += varyingName; - segments->fVSCode += " = "; - segments->fVSCode += vsInCoord; - segments->fVSCode += ";\n"; + segments->fVSCode.appendf("\t%s = %s;\n", varyingName.c_str(), vsInCoord); } else { - segments->fVSCode += "\t"; - segments->fVSCode += varyingName; - segments->fVSCode += " = ("; - segments->fVSCode += texMName; - segments->fVSCode += " * vec3("; - segments->fVSCode += vsInCoord; - segments->fVSCode += ", 1))"; - segments->fVSCode += vector_all_coords(varyingDims); - segments->fVSCode += ";\n"; - } - - GrTokenString radial2ParamsName; + // varying = texMatrix * texCoord + segments->fVSCode.appendf("\t%s = (%s * vec3(%s, 1))%s;\n", + varyingName.c_str(), texMName.c_str(), + vsInCoord, vector_all_coords(varyingDims)); + } + + GrStringBuilder radial2ParamsName; radial2_param_name(stageNum, &radial2ParamsName); // for radial grads without perspective we can pass the linear // part of the quadratic as a varying. - GrTokenString radial2VaryingName; + GrStringBuilder radial2VaryingName; radial2_varying_name(stageNum, &radial2VaryingName); if (ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping) { - segments->fVSUnis += "uniform "; - segments->fVSUnis += GrPrecision(); - segments->fVSUnis += " float "; - segments->fVSUnis += radial2ParamsName; - segments->fVSUnis += "[6];\n"; - - segments->fFSUnis += "uniform "; - segments->fFSUnis += GrPrecision(); - segments->fFSUnis += " float "; - segments->fFSUnis += radial2ParamsName; - segments->fFSUnis += "[6];\n"; - locations->fRadial2Uni = 1; + segments->fVSUnis.appendf("uniform %s float %s[6];\n", + GrPrecision(), radial2ParamsName.c_str()); + segments->fFSUnis.appendf("uniform float %s[6];\n", + radial2ParamsName.c_str()); + locations->fRadial2Uni = kUseUniform; // if there is perspective we don't interpolate this if (varyingDims == coordDims) { GrAssert(2 == coordDims); - segments->fVaryings += "varying float "; - segments->fVaryings += radial2VaryingName; - segments->fVaryings += ";\n"; - - segments->fVSCode += "\t"; - segments->fVSCode += radial2VaryingName; - segments->fVSCode += " = 2.0 * ("; - segments->fVSCode += radial2ParamsName; - segments->fVSCode += "[2] * "; - segments->fVSCode += varyingName; - segments->fVSCode += ".x "; - segments->fVSCode += " - "; - segments->fVSCode += radial2ParamsName; - segments->fVSCode += "[3]);\n"; + segments->fVaryings.appendf("varying float %s;\n", radial2VaryingName.c_str()); + + // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3]) + segments->fVSCode.appendf("\t%s = 2.0 *(%s[2] * %s.x - %s[3]);\n", + radial2VaryingName.c_str(), radial2ParamsName.c_str(), + varyingName.c_str(), radial2ParamsName.c_str()); } } /// Fragment Shader Stuff - GrTokenString fsCoordName; + GrStringBuilder fsCoordName; // function used to access the shader, may be made projective - GrTokenString texFunc("texture2D"); + GrStringBuilder texFunc("texture2D"); if (desc.fOptFlags & (ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit | ProgramDesc::StageDesc::kNoPerspective_OptFlagBit)) { GrAssert(varyingDims == coordDims); fsCoordName = varyingName; } else { - // if we have to do some non-matrix op on the varyings to get + // if we have to do some special op on the varyings to get // our final tex coords then when in perspective we have to - // do an explicit divide - if (ProgramDesc::StageDesc::kIdentity_CoordMapping == desc.fCoordMapping) { - texFunc += "Proj"; + // do an explicit divide. Otherwise, we can use a Proj func. + if (ProgramDesc::StageDesc::kIdentity_CoordMapping == desc.fCoordMapping && + ProgramDesc::StageDesc::kSingle_FetchMode == desc.fFetchMode) { + texFunc.append("Proj"); fsCoordName = varyingName; } else { - fsCoordName = "tCoord"; - fsCoordName.appendInt(stageNum); - - segments->fFSCode += "\t"; - segments->fFSCode += float_vector_type(coordDims); - segments->fFSCode += " "; - segments->fFSCode += fsCoordName; - segments->fFSCode += " = "; - segments->fFSCode += varyingName; - segments->fFSCode += vector_nonhomog_coords(varyingDims); - segments->fFSCode += " / "; - segments->fFSCode += varyingName; - segments->fFSCode += vector_homog_coord(varyingDims); - segments->fFSCode += ";\n"; + fsCoordName = "inCoord"; + fsCoordName.appendS32(stageNum); + segments->fFSCode.appendf("\t%s %s = %s%s / %s%s;\n", + float_vector_type(coordDims), + fsCoordName.c_str(), + varyingName.c_str(), + vector_nonhomog_coords(varyingDims), + varyingName.c_str(), + vector_homog_coord(varyingDims)); } } - GrSStringBuilder<96> sampleCoords; + GrStringBuilder sampleCoords; + bool complexCoord = false; switch (desc.fCoordMapping) { case ProgramDesc::StageDesc::kIdentity_CoordMapping: sampleCoords = fsCoordName; break; case ProgramDesc::StageDesc::kSweepGradient_CoordMapping: - sampleCoords = "vec2(atan(-"; - sampleCoords += fsCoordName; - sampleCoords += ".y, -"; - sampleCoords += fsCoordName; - sampleCoords += ".x)*0.1591549430918 + 0.5, 0.5)"; + sampleCoords.printf("vec2(atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5, 0.5)", fsCoordName.c_str(), fsCoordName.c_str()); + complexCoord = true; break; case ProgramDesc::StageDesc::kRadialGradient_CoordMapping: - sampleCoords = "vec2(length("; - sampleCoords += fsCoordName; - sampleCoords += ".xy), 0.5)"; + sampleCoords.printf("vec2(length(%s.xy), 0.5)", fsCoordName.c_str()); + complexCoord = true; break; case ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping: { - GrTokenString cName = "c"; - GrTokenString ac4Name = "ac4"; - GrTokenString rootName = "root"; + GrStringBuilder cName("c"); + GrStringBuilder ac4Name("ac4"); + GrStringBuilder rootName("root"); - cName.appendInt(stageNum); - ac4Name.appendInt(stageNum); - rootName.appendInt(stageNum); + cName.appendS32(stageNum); + ac4Name.appendS32(stageNum); + rootName.appendS32(stageNum); - GrTokenString bVar; + // if we were able to interpolate the linear component bVar is the varying + // otherwise compute it + GrStringBuilder bVar; if (coordDims == varyingDims) { bVar = radial2VaryingName; GrAssert(2 == varyingDims); } else { GrAssert(3 == varyingDims); bVar = "b"; - bVar.appendInt(stageNum); - segments->fFSCode += "\tfloat "; - segments->fFSCode += bVar; - segments->fFSCode += " = 2.0 * ("; - segments->fFSCode += radial2ParamsName; - segments->fFSCode += "[2] * "; - segments->fFSCode += fsCoordName; - segments->fFSCode += ".x "; - segments->fFSCode += " - "; - segments->fFSCode += radial2ParamsName; - segments->fFSCode += "[3]);\n"; + bVar.appendS32(stageNum); + segments->fFSCode.appendf("\tfloat %s = 2.0 * (%s[2] * %s.x - %s[3]);\n", + bVar.c_str(), radial2ParamsName.c_str(), + fsCoordName.c_str(), radial2ParamsName.c_str()); } - segments->fFSCode += "\tfloat "; - segments->fFSCode += cName; - segments->fFSCode += " = dot("; - segments->fFSCode += fsCoordName; - segments->fFSCode += ", "; - segments->fFSCode += fsCoordName; - segments->fFSCode += ") + "; - segments->fFSCode += " - "; - segments->fFSCode += radial2ParamsName; - segments->fFSCode += "[4];\n"; - - segments->fFSCode += "\tfloat "; - segments->fFSCode += ac4Name; - segments->fFSCode += " = "; - segments->fFSCode += radial2ParamsName; - segments->fFSCode += "[0] * 4.0 * "; - segments->fFSCode += cName; - segments->fFSCode += ";\n"; - - segments->fFSCode += "\tfloat "; - segments->fFSCode += rootName; - segments->fFSCode += " = sqrt(abs("; - segments->fFSCode += bVar; - segments->fFSCode += " * "; - segments->fFSCode += bVar; - segments->fFSCode += " - "; - segments->fFSCode += ac4Name; - segments->fFSCode += "));\n"; - - sampleCoords = "vec2((-"; - sampleCoords += bVar; - sampleCoords += " + "; - sampleCoords += radial2ParamsName; - sampleCoords += "[5] * "; - sampleCoords += rootName; - sampleCoords += ") * "; - sampleCoords += radial2ParamsName; - sampleCoords += "[1], 0.5)\n"; + // c = (x^2)+(y^2) - params[4] + segments->fFSCode.appendf("\tfloat %s = dot(%s, %s) - %s[4];\n", + cName.c_str(), fsCoordName.c_str(), + fsCoordName.c_str(), + radial2ParamsName.c_str()); + // ac4 = 4.0 * params[0] * c + segments->fFSCode.appendf("\tfloat %s = %s[0] * 4.0 * %s;\n", + ac4Name.c_str(), radial2ParamsName.c_str(), + cName.c_str()); + + // root = sqrt(b^2-4ac) + // (abs to avoid exception due to fp precision) + segments->fFSCode.appendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n", + rootName.c_str(), bVar.c_str(), bVar.c_str(), + ac4Name.c_str()); + + // x coord is: (-b + params[5] * sqrt(b^2-4ac)) * params[1] + // y coord is 0.5 (texture is effectively 1D) + sampleCoords.printf("vec2((-%s + %s[5] * %s) * %s[1], 0.5)", + bVar.c_str(), radial2ParamsName.c_str(), + rootName.c_str(), radial2ParamsName.c_str()); + complexCoord = true; break;} }; - segments->fFSCode += "\t"; - segments->fFSCode += fsOutColor; - segments->fFSCode += " = "; - if (NULL != fsInColor) { - segments->fFSCode += fsInColor; - segments->fFSCode += " * "; - } - segments->fFSCode += texFunc; - segments->fFSCode += "("; - segments->fFSCode += samplerName; - segments->fFSCode += ", "; - segments->fFSCode += sampleCoords; - segments->fFSCode += ")"; + const char* smear; if (desc.fModulation == ProgramDesc::StageDesc::kAlpha_Modulation) { - segments->fFSCode += ".aaaa"; + smear = ".aaaa"; + } else { + smear = ""; + } + GrStringBuilder modulate; + if (NULL != fsInColor) { + modulate.printf(" * %s", fsInColor); + } + + if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) { + locations->fNormalizedTexelSizeUni = kUseUniform; + if (complexCoord) { + // assign the coord to a var rather than compute 4x. + GrStringBuilder coordVar("tCoord"); + coordVar.appendS32(stageNum); + segments->fFSCode.appendf("\t%s %s = %s;\n", + float_vector_type(coordDims), + coordVar.c_str(), sampleCoords.c_str()); + sampleCoords = coordVar; + } + GrAssert(2 == coordDims); + GrStringBuilder accumVar("accum"); + accumVar.appendS32(stageNum); + segments->fFSCode.appendf("\tvec4 %s = %s(%s, %s + vec2(-%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear); + segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear); + segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(-%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear); + segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear); + segments->fFSCode.appendf("\t%s = .25 * %s%s;\n", fsOutColor, accumVar.c_str(), modulate.c_str()); + } else { + segments->fFSCode.appendf("\t%s = %s(%s, %s)%s %s;\n", fsOutColor, texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), smear, modulate.c_str()); } - segments->fFSCode += ";\n"; if(fStageEffects[stageNum]) { fStageEffects[stageNum]->genShaderCode(segments); diff --git a/gpu/src/GrGLProgram.h b/gpu/src/GrGLProgram.h index 1a15953..1611ca2 100644 --- a/gpu/src/GrGLProgram.h +++ b/gpu/src/GrGLProgram.h @@ -18,13 +18,11 @@ #define GrGLProgram_DEFINED #include "GrGLInterface.h" - -#define POS_ATTR_LOCATION 0 -#define TEX_ATTR_LOCATION(X) (1 + (X)) -#define COL_ATTR_LOCATION (2 + GrDrawTarget::kMaxTexCoords) - +#include "GrStringBuilder.h" #include "GrDrawTarget.h" +#include "SkXfermode.h" + class GrBinHashKeyBuilder; class GrGLEffect; struct ShaderCodeSegments; @@ -58,7 +56,7 @@ public: * The result of heavy init is not stored in datamembers of GrGLProgam, * but in a separate cacheable container. */ - void genProgram(CachedData* programData, const GrDrawTarget* target) const; + bool genProgram(CachedData* programData) const; /** * Routine that is called before rendering. Sets-up all the state and @@ -80,20 +78,39 @@ public: */ void buildFromTarget(const GrDrawTarget* target); + static int PositionAttributeIdx() { return 0; } + static int TexCoordAttributeIdx(int tcIdx) { return 1 + tcIdx; } + static int ColorAttributeIdx() { return 1 + GrDrawTarget::kMaxTexCoords; } + static int ViewMatrixAttributeIdx() { + return 2 + GrDrawTarget::kMaxTexCoords; + } + static int TextureMatrixAttributeIdx(int stage) { + return 5 + GrDrawTarget::kMaxTexCoords + 3 * stage; + } + private: //Parameters that affect code generation struct ProgramDesc { + ProgramDesc() { + // since we use this as part of a key we can't have any unitialized + // padding + memset(this, 0, sizeof(ProgramDesc)); + } + + // stripped of bits that don't affect prog generation GrVertexLayout fVertexLayout; enum { - kNotPoints_OptFlagBit = 0x1, - kVertexColorAllOnes_OptFlagBit = 0x2, - }; - // we're assuming optflags and layout pack into 32 bits - // VS 2010 seems to require short rather than just unsigned - // for this to pack - unsigned short fOptFlags : 16; + kNone_ColorType = 0, + kAttribute_ColorType = 1, + kUniform_ColorType = 2, + } fColorType; + + bool fEmitsPointSize; + bool fUsesEdgeAA; + + SkXfermode::Mode fColorFilterXfermode; struct StageDesc { enum OptFlagBits { @@ -101,33 +118,64 @@ private: kIdentityMatrix_OptFlagBit = 0x2 }; - unsigned fOptFlags : 8; - unsigned fEnabled : 8; + unsigned fOptFlags; + bool fEnabled; enum Modulation { kColor_Modulation, kAlpha_Modulation - } fModulation : 8; + } fModulation; + + enum FetchMode { + kSingle_FetchMode, + k2x2_FetchMode + } fFetchMode; enum CoordMapping { kIdentity_CoordMapping, kRadialGradient_CoordMapping, kSweepGradient_CoordMapping, kRadial2Gradient_CoordMapping - } fCoordMapping : 8; + } fCoordMapping; } fStages[GrDrawTarget::kNumStages]; } fProgramDesc; + const ProgramDesc& getDesc() { return fProgramDesc; } + public: + enum { + kUnusedUniform = -1, + kSetAsAttribute = 1000, + }; + struct StageUniLocations { GrGLint fTextureMatrixUni; + GrGLint fNormalizedTexelSizeUni; GrGLint fSamplerUni; GrGLint fRadial2Uni; + void reset() { + fTextureMatrixUni = kUnusedUniform; + fNormalizedTexelSizeUni = kUnusedUniform; + fSamplerUni = kUnusedUniform; + fRadial2Uni = kUnusedUniform; + } }; struct UniLocations { GrGLint fViewMatrixUni; + GrGLint fColorUni; + GrGLint fEdgesUni; + GrGLint fColorFilterUni; StageUniLocations fStages[GrDrawTarget::kNumStages]; + void reset() { + fViewMatrixUni = kUnusedUniform; + fColorUni = kUnusedUniform; + fEdgesUni = kUnusedUniform; + fColorFilterUni = kUnusedUniform; + for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { + fStages[s].reset(); + } + } }; class CachedData : public ::GrNoncopyable { @@ -142,7 +190,7 @@ public: } void copyAndTakeOwnership(CachedData& other) { - memcpy(this, &other, sizeof(this)); + memcpy(this, &other, sizeof(*this)); other.fEffectUniLocationsExtended = NULL; // ownership transfer GR_DEBUGCODE(other.fEffectUniCount = 0;) } @@ -177,7 +225,12 @@ public: // these reflect the current values of uniforms // (GL uniform values travel with program) + GrColor fColor; + GrColor fColorFilterColor; GrMatrix fTextureMatrices[GrDrawTarget::kNumStages]; + // width and height used for normalized texel size + int fTextureWidth[GrDrawTarget::kNumStages]; + int fTextureHeight[GrDrawTarget::kNumStages]; GrScalar fRadial2CenterX1[GrDrawTarget::kNumStages]; GrScalar fRadial2Radius0[GrDrawTarget::kNumStages]; bool fRadial2PosRoot[GrDrawTarget::kNumStages]; @@ -195,6 +248,12 @@ public: GrGLEffect* fStageEffects[GrDrawTarget::kNumStages]; private: + enum { + kUseUniform = 2000 + }; + + // should set all fields in locations var to kUseUniform if the + // corresponding uniform is required for the program. void genStageCode(int stageNum, const ProgramDesc::StageDesc& desc, const char* fsInColor, // NULL means no incoming color @@ -203,12 +262,24 @@ private: ShaderCodeSegments* segments, StageUniLocations* locations) const; + static bool CompileFSAndVS(const ShaderCodeSegments& segments, + CachedData* programData); + // Compiles a GL shader, returns shader ID or 0 if failed // params have same meaning as glShaderSource static GrGLuint CompileShader(GrGLenum type, int stringCnt, const char** strings, int* stringLengths); + // Creates a GL program ID, binds shader attributes to GL vertex attrs, and + // links the program + bool bindAttribsAndLinkProgram(GrStringBuilder texCoordAttrNames[GrDrawTarget::kMaxTexCoords], + CachedData* programData) const; + + // Gets locations for all uniforms set to kUseUniform and initializes cache + // to invalid values. + void getUniformLocationsAndInitCache(CachedData* programData) const; + friend class GrGpuGLShaders; }; diff --git a/gpu/src/GrGLTexture.cpp b/gpu/src/GrGLTexture.cpp index 3c6504d..d3ccfa6 100644 --- a/gpu/src/GrGLTexture.cpp +++ b/gpu/src/GrGLTexture.cpp @@ -33,7 +33,6 @@ GrGLRenderTarget::GrGLRenderTarget(GrGpuGL* gpu, fTexFBOID = ids.fTexFBOID; fStencilRenderbufferID = ids.fStencilRenderbufferID; fMSColorRenderbufferID = ids.fMSColorRenderbufferID; - fNeedsResolve = false; fViewport = viewport; fOwnIDs = ids.fOwnIDs; fTexIDObj = texID; diff --git a/gpu/src/GrGLUtil.cpp b/gpu/src/GrGLUtil.cpp index 5234453..04e25fd 100644 --- a/gpu/src/GrGLUtil.cpp +++ b/gpu/src/GrGLUtil.cpp @@ -43,6 +43,11 @@ void GrGLRestoreResetRowLength() { /////////////////////////////////////////////////////////////////////////////// -bool gLogCallsGL = !!(GR_GL_LOG_CALLS_START); +#if GR_GL_LOG_CALLS + bool gLogCallsGL = !!(GR_GL_LOG_CALLS_START); +#endif + +#if GR_GL_CHECK_ERROR + bool gCheckErrorGL = !!(GR_GL_CHECK_ERROR_START); +#endif -bool gCheckErrorGL = !!(GR_GL_CHECK_ERROR_START); diff --git a/gpu/src/GrGpu.cpp b/gpu/src/GrGpu.cpp index 43fe648..9950afd 100644 --- a/gpu/src/GrGpu.cpp +++ b/gpu/src/GrGpu.cpp @@ -136,7 +136,7 @@ void GrGpu::unimpl(const char msg[]) { //////////////////////////////////////////////////////////////////////////////// -GrTexture* GrGpu::createTexture(const TextureDesc& desc, +GrTexture* GrGpu::createTexture(const GrTextureDesc& desc, const void* srcData, size_t rowBytes) { this->handleDirtyContext(); return this->onCreateTexture(desc, srcData, rowBytes); @@ -173,9 +173,9 @@ GrIndexBuffer* GrGpu::createIndexBuffer(uint32_t size, bool dynamic) { return this->onCreateIndexBuffer(size, dynamic); } -void GrGpu::eraseColor(GrColor color) { +void GrGpu::clear(const GrIRect* rect, GrColor color) { this->handleDirtyContext(); - this->onEraseColor(color); + this->onClear(rect, color); } void GrGpu::forceRenderTargetFlush() { @@ -238,10 +238,16 @@ const GrVertexBuffer* GrGpu::getUnitSquareVertexBuffer() const { if (NULL == fUnitSquareVertexBuffer) { static const GrPoint DATA[] = { + { 0, 0 }, + { GR_Scalar1, 0 }, + { GR_Scalar1, GR_Scalar1 }, + { 0, GR_Scalar1 } +#if 0 GrPoint(0, 0), GrPoint(GR_Scalar1,0), GrPoint(GR_Scalar1,GR_Scalar1), GrPoint(0, GR_Scalar1) +#endif }; static const size_t SIZE = sizeof(DATA); @@ -393,7 +399,9 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) { GrIntToScalar(rt.width()), GrIntToScalar(rt.height())); if (fClip.hasConservativeBounds()) { bounds = fClip.getConservativeBounds(); - bounds.intersectWith(rtRect); + if (!bounds.intersect(rtRect)) { + bounds.setEmpty(); + } } else { bounds = rtRect; } @@ -423,7 +431,7 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) { AutoInternalDrawGeomRestore aidgr(this); this->setViewMatrix(GrMatrix::I()); - this->eraseStencilClip(clipRect); + this->clearStencilClip(clipRect); this->flushScissor(NULL); #if !VISUALIZE_COMPLEX_CLIP this->enableState(kNoColorWrites_StateBit); @@ -725,7 +733,7 @@ void GrGpu::onSetIndexSourceToArray(const void* indexArray, int indexCount) { //////////////////////////////////////////////////////////////////////////////// -const GrGpu::Stats& GrGpu::getStats() const { +const GrGpuStats& GrGpu::getStats() const { return fStats; } @@ -755,7 +763,7 @@ const GrSamplerState GrSamplerState::gClampNoFilter( GrSamplerState::kClamp_WrapMode, GrSamplerState::kNormal_SampleMode, GrMatrix::I(), - false); + GrSamplerState::kNearest_Filter); diff --git a/gpu/src/GrGpuFactory.cpp b/gpu/src/GrGpuFactory.cpp index 1715333..38c07b7 100644 --- a/gpu/src/GrGpuFactory.cpp +++ b/gpu/src/GrGpuFactory.cpp @@ -26,12 +26,11 @@ #include "GrGpu.h" #include "GrGpuGLFixed.h" #include "GrGpuGLShaders.h" -#include "GrGpuGLShaders2.h" -GrGpu* GrGpu::Create(Engine engine, Platform3DContext context3D) { +GrGpu* GrGpu::Create(GrEngine engine, GrPlatform3DContext context3D) { - if (kOpenGL_Shaders_Engine == engine || - kOpenGL_Fixed_Engine == engine) { + if (kOpenGL_Shaders_GrEngine == engine || + kOpenGL_Fixed_GrEngine == engine) { // If no GL bindings have been installed, fall-back to calling the // GL functions that have been linked with the executable. if (!GrGLGetGLInterface()) { @@ -41,27 +40,33 @@ GrGpu* GrGpu::Create(Engine engine, Platform3DContext context3D) { return NULL; } } + if (!GrGLGetGLInterface()->validate(engine)) { +#if GR_DEBUG + GrPrintf("Failed GL interface validation!"); +#endif + return NULL; + } } GrGpu* gpu = NULL; switch (engine) { - case kOpenGL_Shaders_Engine: - GrAssert(NULL == context3D); + case kOpenGL_Shaders_GrEngine: + GrAssert(NULL == (void*)context3D); { -#if GR_USE_NEW_GLSHADERS - gpu = new GrGpuGLShaders; -#else +#if 0 // old code path, will be removed soon gpu = new GrGpuGLShaders2; +#else + gpu = new GrGpuGLShaders; #endif } break; - case kOpenGL_Fixed_Engine: - GrAssert(NULL == context3D); + case kOpenGL_Fixed_GrEngine: + GrAssert(NULL == (void*)context3D); gpu = new GrGpuGLFixed; break; - case kDirect3D9_Engine: - GrAssert(NULL != context3D); + case kDirect3D9_GrEngine: + GrAssert(NULL != (void*)context3D); #if GR_WIN32_BUILD // gpu = new GrGpuD3D9((IDirect3DDevice9*)context3D); #endif diff --git a/gpu/src/GrGpuGL.cpp b/gpu/src/GrGpuGL.cpp index fe461cc..e8c7afb 100644 --- a/gpu/src/GrGpuGL.cpp +++ b/gpu/src/GrGpuGL.cpp @@ -223,10 +223,10 @@ GrGpuGL::GrGpuGL() { GrPrintf("Palette8 support: %s\n", (f8bitPaletteSupport ? "YES" : "NO")); } - GR_STATIC_ASSERT(0 == kNone_AALevel); - GR_STATIC_ASSERT(1 == kLow_AALevel); - GR_STATIC_ASSERT(2 == kMed_AALevel); - GR_STATIC_ASSERT(3 == kHigh_AALevel); + 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; @@ -268,19 +268,20 @@ GrGpuGL::GrGpuGL() { GrGLint maxSamples; GR_GL_GetIntegerv(GR_GL_MAX_SAMPLES, &maxSamples); if (maxSamples > 1 ) { - fAASamples[kNone_AALevel] = 0; - fAASamples[kLow_AALevel] = GrMax(2, - GrFixedFloorToInt((GR_FixedHalf) * - maxSamples)); - fAASamples[kMed_AALevel] = GrMax(2, - GrFixedFloorToInt(((GR_Fixed1*3)/4) * - maxSamples)); - fAASamples[kHigh_AALevel] = maxSamples; + 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 (GR_GL_SUPPORT_DESKTOP) { fHasStencilWrap = (major >= 2 || (major == 1 && minor >= 4)) || @@ -361,6 +362,8 @@ GrGpuGL::GrGpuGL() { } } + fAALineSupport = GR_GL_SUPPORT_DESKTOP; + //////////////////////////////////////////////////////////////////////////// // Experiments to determine limitations that can't be queried. TODO: Make // these a preprocess that generate some compile time constants. @@ -527,8 +530,7 @@ void GrGpuGL::resetContext() { fHWGeometryState.fIndexBuffer = NULL; fHWGeometryState.fVertexBuffer = NULL; - GR_GL(BindBuffer(GR_GL_ARRAY_BUFFER, 0)); - GR_GL(BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, 0)); + fHWGeometryState.fArrayPtrsDirty = true; GR_GL(ColorMask(GR_GL_TRUE, GR_GL_TRUE, GR_GL_TRUE, GR_GL_TRUE)); @@ -699,7 +701,7 @@ static size_t as_size_t(int x) { } #endif -GrTexture* GrGpuGL::onCreateTexture(const TextureDesc& desc, +GrTexture* GrGpuGL::onCreateTexture(const GrTextureDesc& desc, const void* srcData, size_t rowBytes) { @@ -726,7 +728,7 @@ GrTexture* GrGpuGL::onCreateTexture(const TextureDesc& desc, glDesc.fFormat = desc.fFormat; glDesc.fOwnsID = true; - bool renderTarget = 0 != (desc.fFlags & kRenderTarget_TextureFlag); + bool renderTarget = 0 != (desc.fFlags & kRenderTarget_GrTextureFlagBit); if (!canBeTexture(desc.fFormat, &internalFormat, &glDesc.fUploadFormat, @@ -736,7 +738,7 @@ GrTexture* GrGpuGL::onCreateTexture(const TextureDesc& desc, GrAssert(as_size_t(desc.fAALevel) < GR_ARRAY_COUNT(fAASamples)); GrGLint samples = fAASamples[desc.fAALevel]; - if (kNone_MSFBO == fMSFBOType && desc.fAALevel != kNone_AALevel) { + if (kNone_MSFBO == fMSFBOType && desc.fAALevel != kNone_GrAALevel) { GrPrintf("AA RT requested but not supported on this platform."); } @@ -813,7 +815,7 @@ GrTexture* GrGpuGL::onCreateTexture(const TextureDesc& desc, GrAssert(desc.fWidth == glDesc.fAllocWidth); GrAssert(desc.fHeight == glDesc.fAllocHeight); GrGLsizei imageSize = glDesc.fAllocWidth * glDesc.fAllocHeight + - kColorTableSize; + kGrColorTableSize; GR_GL(CompressedTexImage2D(GR_GL_TEXTURE_2D, 0, glDesc.fUploadFormat, glDesc.fAllocWidth, glDesc.fAllocHeight, 0, imageSize, srcData)); @@ -930,7 +932,7 @@ GrTexture* GrGpuGL::onCreateTexture(const TextureDesc& desc, } else { rtIDs.fRTFBOID = rtIDs.fTexFBOID; } - if (!(kNoStencil_TextureFlag & desc.fFlags)) { + if (!(kNoStencil_GrTextureFlagBit & desc.fFlags)) { GR_GL(GenRenderbuffers(1, &rtIDs.fStencilRenderbufferID)); GrAssert(0 != rtIDs.fStencilRenderbufferID); } @@ -1077,10 +1079,10 @@ GrTexture* GrGpuGL::onCreateTexture(const TextureDesc& desc, fHWDrawState.fRenderTarget = NULL; // clear the new stencil buffer if we have one - if (!(desc.fFlags & kNoStencil_TextureFlag)) { + if (!(desc.fFlags & kNoStencil_GrTextureFlagBit)) { GrRenderTarget* rtSave = fCurrDrawState.fRenderTarget; fCurrDrawState.fRenderTarget = rt; - eraseStencil(0, ~0); + this->clearStencil(0, ~0); fCurrDrawState.fRenderTarget = rtSave; } } @@ -1165,15 +1167,24 @@ void GrGpuGL::flushScissor(const GrIRect* rect) { } } -void GrGpuGL::onEraseColor(GrColor color) { +void GrGpuGL::onClear(const GrIRect* rect, GrColor color) { if (NULL == fCurrDrawState.fRenderTarget) { return; } - flushRenderTarget(); - if (fHWBounds.fScissorEnabled) { - GR_GL(Disable(GR_GL_SCISSOR_TEST)); - fHWBounds.fScissorEnabled = false; + GrIRect r; + if (NULL != rect) { + // flushScissor expects rect to be clipped to the target. + r = *rect; + GrIRect rtRect = SkIRect::MakeWH(fCurrDrawState.fRenderTarget->width(), + fCurrDrawState.fRenderTarget->height()); + if (r.intersect(rtRect)) { + rect = &r; + } else { + return; + } } + this->flushRenderTarget(rect); + this->flushScissor(rect); GR_GL(ColorMask(GR_GL_TRUE,GR_GL_TRUE,GR_GL_TRUE,GR_GL_TRUE)); fHWDrawState.fFlagBits &= ~kNoColorWrites_StateBit; GR_GL(ClearColor(GrColorUnpackR(color)/255.f, @@ -1183,11 +1194,13 @@ void GrGpuGL::onEraseColor(GrColor color) { GR_GL(Clear(GR_GL_COLOR_BUFFER_BIT)); } -void GrGpuGL::eraseStencil(uint32_t value, uint32_t mask) { +void GrGpuGL::clearStencil(uint32_t value, uint32_t mask) { if (NULL == fCurrDrawState.fRenderTarget) { return; } - flushRenderTarget(); + + this->flushRenderTarget(&GrIRect::EmptyIRect()); + if (fHWBounds.fScissorEnabled) { GR_GL(Disable(GR_GL_SCISSOR_TEST)); fHWBounds.fScissorEnabled = false; @@ -1198,7 +1211,7 @@ void GrGpuGL::eraseStencil(uint32_t value, uint32_t mask) { fHWDrawState.fStencilSettings.invalidate(); } -void GrGpuGL::eraseStencilClip(const GrIRect& rect) { +void GrGpuGL::clearStencilClip(const GrIRect& rect) { GrAssert(NULL != fCurrDrawState.fRenderTarget); #if 0 GrGLint stencilBitCount = fCurrDrawState.fRenderTarget->stencilBits(); @@ -1212,7 +1225,7 @@ void GrGpuGL::eraseStencilClip(const GrIRect& rect) { // zero the client's clip bits. So we just clear the whole thing. static const GrGLint clipStencilMask = ~0; #endif - flushRenderTarget(); + this->flushRenderTarget(&GrIRect::EmptyIRect()); flushScissor(&rect); GR_GL(StencilMask(clipStencilMask)); GR_GL(ClearStencil(0)); @@ -1221,7 +1234,7 @@ void GrGpuGL::eraseStencilClip(const GrIRect& rect) { } void GrGpuGL::onForceRenderTargetFlush() { - flushRenderTarget(); + this->flushRenderTarget(&GrIRect::EmptyIRect()); } bool GrGpuGL::onReadPixels(GrRenderTarget* target, @@ -1241,10 +1254,10 @@ bool GrGpuGL::onReadPixels(GrRenderTarget* target, case GrGLRenderTarget::kAutoResolves_ResolveType: autoTargetRestore.save(&fCurrDrawState.fRenderTarget); fCurrDrawState.fRenderTarget = target; - flushRenderTarget(); + this->flushRenderTarget(&GrIRect::EmptyIRect()); break; case GrGLRenderTarget::kCanResolve_ResolveType: - resolveRenderTarget(tgt); + this->resolveRenderTarget(tgt); // we don't track the state of the READ FBO ID. GR_GL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER, tgt->textureFBOID())); break; @@ -1282,17 +1295,16 @@ bool GrGpuGL::onReadPixels(GrRenderTarget* target, return true; } -void GrGpuGL::flushRenderTarget() { +void GrGpuGL::flushRenderTarget(const GrIRect* bound) { GrAssert(NULL != fCurrDrawState.fRenderTarget); + GrGLRenderTarget* rt = (GrGLRenderTarget*)fCurrDrawState.fRenderTarget; if (fHWDrawState.fRenderTarget != fCurrDrawState.fRenderTarget) { - GrGLRenderTarget* rt = (GrGLRenderTarget*)fCurrDrawState.fRenderTarget; GR_GL(BindFramebuffer(GR_GL_FRAMEBUFFER, rt->renderFBOID())); #if GR_COLLECT_STATS ++fStats.fRenderTargetChngCnt; #endif - rt->flagAsNeedingResolve(); #if GR_DEBUG GrGLenum status = GR_GL(CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); if (status != GR_GL_FRAMEBUFFER_COMPLETE) { @@ -1307,6 +1319,9 @@ void GrGpuGL::flushRenderTarget() { fHWBounds.fViewportRect = vp; } } + if (NULL == bound || !bound->isEmpty()) { + rt->flagAsNeedingResolve(bound); + } } GrGLenum gPrimitiveType2GLMode[] = { @@ -1416,12 +1431,16 @@ void GrGpuGL::resolveRenderTarget(GrGLRenderTarget* rt) { // the bound DRAW FBO ID. fHWDrawState.fRenderTarget = NULL; const GrGLIRect& vp = rt->getViewport(); + const GrIRect dirtyRect = rt->getResolveRect(); + GrGLIRect r; + r.setRelativeTo(vp, dirtyRect.fLeft, dirtyRect.fTop, + dirtyRect.width(), dirtyRect.height()); if (kAppleES_MSFBO == fMSFBOType) { // Apple's extension uses the scissor as the blit bounds. GR_GL(Enable(GR_GL_SCISSOR_TEST)); - GR_GL(Scissor(vp.fLeft, vp.fBottom, - vp.fWidth, vp.fHeight)); + GR_GL(Scissor(r.fLeft, r.fBottom, + r.fWidth, r.fHeight)); GR_GL(ResolveMultisampleFramebuffer()); fHWBounds.fScissorRect.invalidate(); fHWBounds.fScissorEnabled = true; @@ -1431,10 +1450,10 @@ void GrGpuGL::resolveRenderTarget(GrGLRenderTarget* rt) { GrAssert(kDesktopEXT_MSFBO == fMSFBOType); flushScissor(NULL); } - int right = vp.fLeft + vp.fWidth; - int top = vp.fBottom + vp.fHeight; - GR_GL(BlitFramebuffer(vp.fLeft, vp.fBottom, right, top, - vp.fLeft, vp.fBottom, right, top, + int right = r.fLeft + r.fWidth; + int top = r.fBottom + r.fHeight; + GR_GL(BlitFramebuffer(r.fLeft, r.fBottom, right, top, + r.fLeft, r.fBottom, right, top, GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST)); } rt->flagAsResolved(); @@ -1703,81 +1722,87 @@ bool GrGpuGL::flushGLStateCommon(GrPrimitiveType type) { GrAssert(NULL != fCurrDrawState.fRenderTarget); for (int s = 0; s < kNumStages; ++s) { - bool usingTexture = VertexUsesStage(s, fGeometrySrc.fVertexLayout); - // bind texture and set sampler state - if (usingTexture) { + if (this->isStageEnabled(s)) { GrGLTexture* nextTexture = (GrGLTexture*)fCurrDrawState.fTextures[s]; - if (NULL != nextTexture) { - // if we created a rt/tex and rendered to it without using a - // texture and now we're texuring from the rt it will still be - // the last bound texture, but it needs resolving. So keep this - // out of the "last != next" check. - GrGLRenderTarget* texRT = - static_cast<GrGLRenderTarget*>(nextTexture->asRenderTarget()); - if (NULL != texRT) { - resolveRenderTarget(texRT); - } + // true for now, but maybe not with GrEffect. + GrAssert(NULL != nextTexture); + // if we created a rt/tex and rendered to it without using a + // texture and now we're texuring from the rt it will still be + // the last bound texture, but it needs resolving. So keep this + // out of the "last != next" check. + GrGLRenderTarget* texRT = + static_cast<GrGLRenderTarget*>(nextTexture->asRenderTarget()); + if (NULL != texRT) { + resolveRenderTarget(texRT); + } - if (fHWDrawState.fTextures[s] != nextTexture) { - setTextureUnit(s); - GR_GL(BindTexture(GR_GL_TEXTURE_2D, nextTexture->textureID())); - #if GR_COLLECT_STATS - ++fStats.fTextureChngCnt; - #endif - //GrPrintf("---- bindtexture %d\n", nextTexture->textureID()); - fHWDrawState.fTextures[s] = nextTexture; - } + if (fHWDrawState.fTextures[s] != nextTexture) { + setTextureUnit(s); + GR_GL(BindTexture(GR_GL_TEXTURE_2D, nextTexture->textureID())); + #if GR_COLLECT_STATS + ++fStats.fTextureChngCnt; + #endif + //GrPrintf("---- bindtexture %d\n", nextTexture->textureID()); + fHWDrawState.fTextures[s] = nextTexture; + } - const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s]; - const GrGLTexture::TexParams& oldTexParams = - nextTexture->getTexParams(); - GrGLTexture::TexParams newTexParams; - - newTexParams.fFilter = sampler.isFilter() ? GR_GL_LINEAR : - GR_GL_NEAREST; - newTexParams.fWrapS = - GrGLTexture::WrapMode2GLWrap()[sampler.getWrapX()]; - newTexParams.fWrapT = - GrGLTexture::WrapMode2GLWrap()[sampler.getWrapY()]; - - if (newTexParams.fFilter != oldTexParams.fFilter) { - setTextureUnit(s); - GR_GL(TexParameteri(GR_GL_TEXTURE_2D, - GR_GL_TEXTURE_MAG_FILTER, - newTexParams.fFilter)); - GR_GL(TexParameteri(GR_GL_TEXTURE_2D, - GR_GL_TEXTURE_MIN_FILTER, - newTexParams.fFilter)); - } - if (newTexParams.fWrapS != oldTexParams.fWrapS) { - setTextureUnit(s); - GR_GL(TexParameteri(GR_GL_TEXTURE_2D, - GR_GL_TEXTURE_WRAP_S, - newTexParams.fWrapS)); - } - if (newTexParams.fWrapT != oldTexParams.fWrapT) { - setTextureUnit(s); - GR_GL(TexParameteri(GR_GL_TEXTURE_2D, - GR_GL_TEXTURE_WRAP_T, - newTexParams.fWrapT)); - } - nextTexture->setTexParams(newTexParams); + const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s]; + const GrGLTexture::TexParams& oldTexParams = + nextTexture->getTexParams(); + GrGLTexture::TexParams newTexParams; - // The texture matrix has to compensate for texture width/height - // and NPOT-embedded-in-POT - fDirtyFlags.fTextureChangedMask |= (1 << s); + if (GrSamplerState::kNearest_Filter == sampler.getFilter()) { + newTexParams.fFilter = GR_GL_NEAREST; } else { - GrAssert(!"Rendering with texture vert flag set but no texture"); - return false; + newTexParams.fFilter = GR_GL_LINEAR; + } + + newTexParams.fWrapS = + GrGLTexture::WrapMode2GLWrap()[sampler.getWrapX()]; + newTexParams.fWrapT = + GrGLTexture::WrapMode2GLWrap()[sampler.getWrapY()]; + + if (newTexParams.fFilter != oldTexParams.fFilter) { + setTextureUnit(s); + GR_GL(TexParameteri(GR_GL_TEXTURE_2D, + GR_GL_TEXTURE_MAG_FILTER, + newTexParams.fFilter)); + GR_GL(TexParameteri(GR_GL_TEXTURE_2D, + GR_GL_TEXTURE_MIN_FILTER, + newTexParams.fFilter)); + } + if (newTexParams.fWrapS != oldTexParams.fWrapS) { + setTextureUnit(s); + GR_GL(TexParameteri(GR_GL_TEXTURE_2D, + GR_GL_TEXTURE_WRAP_S, + newTexParams.fWrapS)); } + if (newTexParams.fWrapT != oldTexParams.fWrapT) { + setTextureUnit(s); + GR_GL(TexParameteri(GR_GL_TEXTURE_2D, + GR_GL_TEXTURE_WRAP_T, + newTexParams.fWrapT)); + } + nextTexture->setTexParams(newTexParams); + + // The texture matrix has to compensate for texture width/height + // and NPOT-embedded-in-POT + fDirtyFlags.fTextureChangedMask |= (1 << s); } } - flushRenderTarget(); - flushAAState(type); - flushBlend(type); + GrIRect* rect = NULL; + GrIRect clipBounds; + if ((fCurrDrawState.fFlagBits & kClip_StateBit) && + fClip.hasConservativeBounds()) { + fClip.getConservativeBounds().roundOut(&clipBounds); + rect = &clipBounds; + } + this->flushRenderTarget(rect); + this->flushAAState(type); + this->flushBlend(type); if ((fCurrDrawState.fFlagBits & kDither_StateBit) != (fHWDrawState.fFlagBits & kDither_StateBit)) { @@ -1821,7 +1846,7 @@ bool GrGpuGL::flushGLStateCommon(GrPrimitiveType type) { #if GR_DEBUG // check for circular rendering for (int s = 0; s < kNumStages; ++s) { - GrAssert(!VertexUsesStage(s, fGeometrySrc.fVertexLayout) || + GrAssert(!this->isStageEnabled(s) || NULL == fCurrDrawState.fRenderTarget || NULL == fCurrDrawState.fTextures[s] || fCurrDrawState.fTextures[s]->asRenderTarget() != diff --git a/gpu/src/GrGpuGL.h b/gpu/src/GrGpuGL.h index eaeec5e..da955cf 100644 --- a/gpu/src/GrGpuGL.h +++ b/gpu/src/GrGpuGL.h @@ -27,10 +27,11 @@ class GrGpuGL : public GrGpu { public: - GrGpuGL(); virtual ~GrGpuGL(); protected: + GrGpuGL(); + struct { size_t fVertexOffset; GrVertexLayout fVertexLayout; @@ -72,7 +73,7 @@ protected: // overrides from GrGpu virtual void resetContext(); - virtual GrTexture* onCreateTexture(const TextureDesc& desc, + virtual GrTexture* onCreateTexture(const GrTextureDesc& desc, const void* srcData, size_t rowBytes); virtual GrVertexBuffer* onCreateVertexBuffer(uint32_t size, @@ -87,7 +88,7 @@ protected: int width, int height); virtual GrRenderTarget* onCreateRenderTargetFrom3DApiState(); - virtual void onEraseColor(GrColor color); + virtual void onClear(const GrIRect* rect, GrColor color); virtual void onForceRenderTargetFlush(); @@ -104,8 +105,8 @@ protected: uint32_t vertexCount, uint32_t numVertices); virtual void flushScissor(const GrIRect* rect); - void eraseStencil(uint32_t value, uint32_t mask); - virtual void eraseStencilClip(const GrIRect& rect); + void clearStencil(uint32_t value, uint32_t mask); + virtual void clearStencilClip(const GrIRect& rect); // binds texture unit in GL void setTextureUnit(int unitIdx); @@ -140,6 +141,7 @@ protected: static bool BlendCoefReferencesConstant(GrBlendCoeff coeff); private: + // notify callbacks to update state tracking when related // objects are bound to GL or deleted outside of the class void notifyVertexBufferBind(const GrGLVertexBuffer* buffer); @@ -153,7 +155,9 @@ private: bool useSmoothLines(); - void flushRenderTarget(); + // bound is region that may be modified and therefore has to be resolved. + // NULL means whole target. Can be an empty rect. + void flushRenderTarget(const GrIRect* bound); void flushStencil(); void flushAAState(GrPrimitiveType type); void flushBlend(GrPrimitiveType type); diff --git a/gpu/src/GrGpuGLFixed.cpp b/gpu/src/GrGpuGLFixed.cpp index 446949f..e197a82 100644 --- a/gpu/src/GrGpuGLFixed.cpp +++ b/gpu/src/GrGpuGLFixed.cpp @@ -32,17 +32,17 @@ struct GrGpuMatrix { void set(const GrMatrix& m) { Gr_bzero(fMat, sizeof(fMat)); - fMat[0] = GrScalarToFloat(m[GrMatrix::kScaleX]); - fMat[4] = GrScalarToFloat(m[GrMatrix::kSkewX]); - fMat[12] = GrScalarToFloat(m[GrMatrix::kTransX]); + fMat[0] = GrScalarToFloat(m[GrMatrix::kMScaleX]); + fMat[4] = GrScalarToFloat(m[GrMatrix::kMSkewX]); + fMat[12] = GrScalarToFloat(m[GrMatrix::kMTransX]); - fMat[1] = GrScalarToFloat(m[GrMatrix::kSkewY]); - fMat[5] = GrScalarToFloat(m[GrMatrix::kScaleY]); - fMat[13] = GrScalarToFloat(m[GrMatrix::kTransY]); + fMat[1] = GrScalarToFloat(m[GrMatrix::kMSkewY]); + fMat[5] = GrScalarToFloat(m[GrMatrix::kMScaleY]); + fMat[13] = GrScalarToFloat(m[GrMatrix::kMTransY]); - fMat[3] = GrScalarToFloat(m[GrMatrix::kPersp0]); - fMat[7] = GrScalarToFloat(m[GrMatrix::kPersp1]); - fMat[15] = GrScalarToFloat(m[GrMatrix::kPersp2]); + fMat[3] = GrScalarToFloat(m[GrMatrix::kMPersp0]); + fMat[7] = GrScalarToFloat(m[GrMatrix::kMPersp1]); + fMat[15] = GrScalarToFloat(m[GrMatrix::kMPersp2]); fMat[10] = 1.f; // z-scale } @@ -56,6 +56,7 @@ static const GrGLenum gMatrixMode2Enum[] = { /////////////////////////////////////////////////////////////////////////////// GrGpuGLFixed::GrGpuGLFixed() { + f4X4DownsampleFilterSupport = false; } GrGpuGLFixed::~GrGpuGLFixed() { @@ -127,8 +128,7 @@ bool GrGpuGLFixed::flushGraphicsState(GrPrimitiveType type) { bool usingTextures[kNumStages]; for (int s = 0; s < kNumStages; ++s) { - usingTextures[s] = VertexUsesStage(s, fGeometrySrc.fVertexLayout); - + usingTextures[s] = this->isStageEnabled(s); if (usingTextures[s] && fCurrDrawState.fSamplerStates[s].isGradient()) { unimpl("Fixed pipe doesn't support radial/sweep gradients"); return false; @@ -152,7 +152,7 @@ bool GrGpuGLFixed::flushGraphicsState(GrPrimitiveType type) { } for (int s = 0; s < kNumStages; ++s) { - bool wasUsingTexture = VertexUsesStage(s, fHWGeometryState.fVertexLayout); + bool wasUsingTexture = StageWillBeUsed(s, fHWGeometryState.fVertexLayout, fHWDrawState); if (usingTextures[s] != wasUsingTexture) { setTextureUnit(s); if (usingTextures[s]) { diff --git a/gpu/src/GrGpuGLShaders.cpp b/gpu/src/GrGpuGLShaders.cpp index b34fc33..8965b06 100644 --- a/gpu/src/GrGpuGLShaders.cpp +++ b/gpu/src/GrGpuGLShaders.cpp @@ -22,18 +22,11 @@ #include "GrMemory.h" #include "GrNoncopyable.h" #include "GrStringBuilder.h" +#include "GrRandom.h" -#define ATTRIBUTE_MATRIX 0 -#define PRINT_SHADERS 0 #define SKIP_CACHE_CHECK true #define GR_UINT32_MAX static_cast<uint32_t>(-1) -#if ATTRIBUTE_MATRIX -#define VIEWMAT_ATTR_LOCATION (3 + GrDrawTarget::kMaxTexCoords) -#define TEXMAT_ATTR_LOCATION(X) (6 + GrDrawTarget::kMaxTexCoords + 3 * (X)) -#define BOGUS_MATRIX_UNI_LOCATION 1000 -#endif - #include "GrTHashCache.h" class GrGpuGLShaders::ProgramCache : public ::GrNoncopyable { @@ -43,17 +36,16 @@ private: #if GR_DEBUG typedef GrBinHashKey<Entry, 4> ProgramHashKey; // Flex the dynamic allocation muscle in debug #else - typedef GrBinHashKey<Entry, 32> ProgramHashKey; + typedef GrBinHashKey<Entry, 64> ProgramHashKey; #endif class Entry : public ::GrNoncopyable { public: Entry() {} - private: void copyAndTakeOwnership(Entry& entry) { fProgramData.copyAndTakeOwnership(entry.fProgramData); fKey.copyAndTakeOwnership(entry.fKey); // ownership transfer - fLRUStamp = entry.fLRUStamp; + fLRUStamp = entry.fLRUStamp; } public: @@ -67,6 +59,8 @@ private: GrTHashTable<Entry, ProgramHashKey, 8> fHashCache; + // We may have kMaxEntries+1 shaders in the GL context because + // we create a new shader before evicting from the cache. enum { kMaxEntries = 32 }; @@ -97,14 +91,16 @@ public: } } - GrGLProgram::CachedData* getProgramData(const GrGLProgram& desc, - const GrDrawTarget* target) { - ProgramHashKey key; - while (key.doPass()) { - desc.buildKey(key); + GrGLProgram::CachedData* getProgramData(const GrGLProgram& desc) { + Entry newEntry; + while (newEntry.fKey.doPass()) { + desc.buildKey(newEntry.fKey); } - Entry* entry = fHashCache.find(key); + Entry* entry = fHashCache.find(newEntry.fKey); if (NULL == entry) { + if (!desc.genProgram(&newEntry.fProgramData)) { + return NULL; + } if (fCount < kMaxEntries) { entry = fEntries + fCount; ++fCount; @@ -119,8 +115,7 @@ public: fHashCache.remove(entry->fKey, entry); GrGpuGLShaders::DeleteProgram(&entry->fProgramData); } - entry->fKey.copyAndTakeOwnership(key); - desc.genProgram(&entry->fProgramData, target); + entry->copyAndTakeOwnership(newEntry); fHashCache.insert(entry->fKey, entry); } @@ -143,13 +138,99 @@ void GrGpuGLShaders::DeleteProgram(GrGLProgram::CachedData* programData) { GR_DEBUGCODE(memset(programData, 0, sizeof(*programData));) } +void GrGpuGLShaders::ProgramUnitTest() { + + static const int STAGE_OPTS[] = { + 0, + GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit, + GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping + }; + static const GrGLProgram::ProgramDesc::StageDesc::Modulation STAGE_MODULATES[] = { + GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation, + GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation + }; + static const GrGLProgram::ProgramDesc::StageDesc::CoordMapping STAGE_COORD_MAPPINGS[] = { + GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping, + GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping, + GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping, + GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping + }; + static const GrGLProgram::ProgramDesc::StageDesc::FetchMode FETCH_MODES[] = { + GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode, + GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode, + }; + GrGLProgram program; + GrGLProgram::ProgramDesc& pdesc = program.fProgramDesc; + + static const int NUM_TESTS = 512; + + // GrRandoms nextU() values have patterns in the low bits + // So using nextU() % array_count might never take some values. + GrRandom random; + for (int t = 0; t < NUM_TESTS; ++t) { + + pdesc.fVertexLayout = 0; + pdesc.fEmitsPointSize = random.nextF() > .5f; + float colorType = random.nextF(); + if (colorType < 1.f / 3.f) { + pdesc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType; + } else if (colorType < 2.f / 3.f) { + pdesc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType; + } else { + pdesc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType; + } + for (int s = 0; s < kNumStages; ++s) { + // enable the stage? + if (random.nextF() > .5f) { + // use separate tex coords? + if (random.nextF() > .5f) { + int t = (int)(random.nextF() * kMaxTexCoords); + pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t); + } else { + pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s); + } + } + // use text-formatted verts? + if (random.nextF() > .5f) { + pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit; + } + } + + for (int s = 0; s < kNumStages; ++s) { + int x; + pdesc.fStages[s].fEnabled = VertexUsesStage(s, pdesc.fVertexLayout); + x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS)); + pdesc.fStages[s].fOptFlags = STAGE_OPTS[x]; + x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES)); + pdesc.fStages[s].fModulation = STAGE_MODULATES[x]; + x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS)); + pdesc.fStages[s].fCoordMapping = STAGE_COORD_MAPPINGS[x]; + x = (int)(random.nextF() * GR_ARRAY_COUNT(FETCH_MODES)); + pdesc.fStages[s].fFetchMode = FETCH_MODES[x]; + } + GrGLProgram::CachedData cachedData; + program.genProgram(&cachedData); + DeleteProgram(&cachedData); + bool again = false; + if (again) { + program.genProgram(&cachedData); + DeleteProgram(&cachedData); + } + } +} + GrGpuGLShaders::GrGpuGLShaders() { resetContext(); + f4X4DownsampleFilterSupport = true; fProgramData = NULL; fProgramCache = new ProgramCache(); + +#if 0 + ProgramUnitTest(); +#endif } GrGpuGLShaders::~GrGpuGLShaders() { @@ -157,21 +238,24 @@ GrGpuGLShaders::~GrGpuGLShaders() { } const GrMatrix& GrGpuGLShaders::getHWSamplerMatrix(int stage) { -#if ATTRIBUTE_MATRIX - return fHWDrawState.fSamplerStates[stage].getMatrix(); -#else GrAssert(fProgramData); - return fProgramData->fTextureMatrices[stage]; -#endif + + if (GrGLProgram::kSetAsAttribute == + fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) { + return fHWDrawState.fSamplerStates[stage].getMatrix(); + } else { + return fProgramData->fTextureMatrices[stage]; + } } void GrGpuGLShaders::recordHWSamplerMatrix(int stage, const GrMatrix& matrix) { -#if ATTRIBUTE_MATRIX - fHWDrawState.fSamplerStates[stage].setMatrix(matrix); -#else GrAssert(fProgramData); - fProgramData->fTextureMatrices[stage] = matrix; -#endif + if (GrGLProgram::kSetAsAttribute == + fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) { + fHWDrawState.fSamplerStates[stage].setMatrix(matrix); + } else { + fProgramData->fTextureMatrices[stage] = matrix; + } } void GrGpuGLShaders::resetContext() { @@ -179,18 +263,19 @@ void GrGpuGLShaders::resetContext() { fHWGeometryState.fVertexLayout = 0; fHWGeometryState.fVertexOffset = ~0; - GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION)); + GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx())); for (int t = 0; t < kMaxTexCoords; ++t) { - GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION(t))); + GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t))); } - GR_GL(EnableVertexAttribArray(POS_ATTR_LOCATION)); + GR_GL(EnableVertexAttribArray(GrGLProgram::PositionAttributeIdx())); fHWProgramID = 0; } void GrGpuGLShaders::flushViewMatrix() { GrAssert(NULL != fCurrDrawState.fRenderTarget); - GrMatrix m ( + GrMatrix m; + m.setAll( GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1, 0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1, 0, 0, GrMatrix::I()[8]); @@ -199,80 +284,187 @@ void GrGpuGLShaders::flushViewMatrix() { // ES doesn't allow you to pass true to the transpose param, // so do our own transpose GrScalar mt[] = { - m[GrMatrix::kScaleX], - m[GrMatrix::kSkewY], - m[GrMatrix::kPersp0], - m[GrMatrix::kSkewX], - m[GrMatrix::kScaleY], - m[GrMatrix::kPersp1], - m[GrMatrix::kTransX], - m[GrMatrix::kTransY], - m[GrMatrix::kPersp2] + m[GrMatrix::kMScaleX], + m[GrMatrix::kMSkewY], + m[GrMatrix::kMPersp0], + m[GrMatrix::kMSkewX], + m[GrMatrix::kMScaleY], + m[GrMatrix::kMPersp1], + m[GrMatrix::kMTransX], + m[GrMatrix::kMTransY], + m[GrMatrix::kMPersp2] }; -#if ATTRIBUTE_MATRIX - GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+0, mt+0)); - GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+1, mt+3)); - GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+2, mt+6)); -#else - GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni,1,false,mt)); -#endif + + if (GrGLProgram::kSetAsAttribute == + fProgramData->fUniLocations.fViewMatrixUni) { + int baseIdx = GrGLProgram::ViewMatrixAttributeIdx(); + GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0)); + GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3)); + GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6)); + } else { + GrAssert(GrGLProgram::kUnusedUniform != + fProgramData->fUniLocations.fViewMatrixUni); + GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni, + 1, false, mt)); + } } -void GrGpuGLShaders::flushTextureMatrix(int stage) { - GrAssert(NULL != fCurrDrawState.fTextures[stage]); +void GrGpuGLShaders::flushTextureMatrix(int s) { + const int& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni; + GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; + if (NULL != texture) { + if (GrGLProgram::kUnusedUniform != uni && + (((1 << s) & fDirtyFlags.fTextureChangedMask) || + getHWSamplerMatrix(s) != getSamplerMatrix(s))) { - GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[stage]; + GrAssert(NULL != fCurrDrawState.fTextures[s]); - GrMatrix m = getSamplerMatrix(stage); - GrSamplerState::SampleMode mode = - fCurrDrawState.fSamplerStates[0].getSampleMode(); - AdjustTextureMatrix(texture, mode, &m); + GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; - // ES doesn't allow you to pass true to the transpose param, - // so do our own transpose - GrScalar mt[] = { - m[GrMatrix::kScaleX], - m[GrMatrix::kSkewY], - m[GrMatrix::kPersp0], - m[GrMatrix::kSkewX], - m[GrMatrix::kScaleY], - m[GrMatrix::kPersp1], - m[GrMatrix::kTransX], - m[GrMatrix::kTransY], - m[GrMatrix::kPersp2] - }; -#if ATTRIBUTE_MATRIX - GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+0, mt+0)); - GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+1, mt+3)); - GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+2, mt+6)); -#else - GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni, - 1, false, mt)); -#endif + GrMatrix m = getSamplerMatrix(s); + GrSamplerState::SampleMode mode = + fCurrDrawState.fSamplerStates[s].getSampleMode(); + AdjustTextureMatrix(texture, mode, &m); + + // ES doesn't allow you to pass true to the transpose param, + // so do our own transpose + GrScalar mt[] = { + m[GrMatrix::kMScaleX], + m[GrMatrix::kMSkewY], + m[GrMatrix::kMPersp0], + m[GrMatrix::kMSkewX], + m[GrMatrix::kMScaleY], + m[GrMatrix::kMPersp1], + m[GrMatrix::kMTransX], + m[GrMatrix::kMTransY], + m[GrMatrix::kMPersp2] + }; + if (GrGLProgram::kSetAsAttribute == + fProgramData->fUniLocations.fStages[s].fTextureMatrixUni) { + int baseIdx = GrGLProgram::TextureMatrixAttributeIdx(s); + GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0)); + GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3)); + GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6)); + } else { + GR_GL(UniformMatrix3fv(uni, 1, false, mt)); + } + recordHWSamplerMatrix(s, getSamplerMatrix(s)); + } + } } -void GrGpuGLShaders::flushRadial2(int stage) { +void GrGpuGLShaders::flushRadial2(int s) { + + const int &uni = fProgramData->fUniLocations.fStages[s].fRadial2Uni; + const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s]; + if (GrGLProgram::kUnusedUniform != uni && + (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() || + fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() || + fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) { + + GrScalar centerX1 = sampler.getRadial2CenterX1(); + GrScalar radius0 = sampler.getRadial2Radius0(); + + GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1; + + float values[6] = { + GrScalarToFloat(a), + 1 / (2.f * values[0]), + GrScalarToFloat(centerX1), + GrScalarToFloat(radius0), + GrScalarToFloat(GrMul(radius0, radius0)), + sampler.isRadial2PosRoot() ? 1.f : -1.f + }; + GR_GL(Uniform1fv(uni, 6, values)); + fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1(); + fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0(); + fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot(); + } +} - const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[stage]; +void GrGpuGLShaders::flushTexelSize(int s) { + const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni; + if (GrGLProgram::kUnusedUniform != uni) { + GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; + if (texture->allocWidth() != fProgramData->fTextureWidth[s] || + texture->allocHeight() != fProgramData->fTextureWidth[s]) { - GrScalar centerX1 = sampler.getRadial2CenterX1(); - GrScalar radius0 = sampler.getRadial2Radius0(); + float texelSize[] = {1.f / texture->allocWidth(), + 1.f / texture->allocHeight()}; + GR_GL(Uniform2fv(uni, 1, texelSize)); + } + } +} - GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1; +void GrGpuGLShaders::flushEdgeAAData() { + const int& uni = fProgramData->fUniLocations.fEdgesUni; + if (GrGLProgram::kUnusedUniform != uni) { + float edges[18]; + memcpy(edges, fCurrDrawState.fEdgeAAEdges, sizeof(edges)); + // Flip the edges in Y + float height = fCurrDrawState.fRenderTarget->height(); + for (int i = 0; i < 6; ++i) { + float b = edges[i * 3 + 1]; + edges[i * 3 + 1] = -b; + edges[i * 3 + 2] += b * height; + } + GR_GL(Uniform3fv(uni, 6, edges)); + } +} - float unis[6] = { - GrScalarToFloat(a), - 1 / (2.f * unis[0]), - GrScalarToFloat(centerX1), - GrScalarToFloat(radius0), - GrScalarToFloat(GrMul(radius0, radius0)), - sampler.isRadial2PosRoot() ? 1.f : -1.f - }; - GR_GL(Uniform1fv(fProgramData->fUniLocations.fStages[stage].fRadial2Uni, - 6, - unis)); +static const float ONE_OVER_255 = 1.f / 255.f; + +#define GR_COLOR_TO_VEC4(color) {\ + GrColorUnpackR(color) * ONE_OVER_255,\ + GrColorUnpackG(color) * ONE_OVER_255,\ + GrColorUnpackB(color) * ONE_OVER_255,\ + GrColorUnpackA(color) * ONE_OVER_255 \ +} + +void GrGpuGLShaders::flushColor() { + const GrGLProgram::ProgramDesc& desc = fCurrentProgram.getDesc(); + if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) { + // color will be specified per-vertex as an attribute + // invalidate the const vertex attrib color + fHWDrawState.fColor = GrColor_ILLEGAL; + } else { + switch (desc.fColorType) { + case GrGLProgram::ProgramDesc::kAttribute_ColorType: + if (fHWDrawState.fColor != fCurrDrawState.fColor) { + // OpenGL ES only supports the float varities of glVertexAttrib + float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor); + GR_GL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c)); + fHWDrawState.fColor = fCurrDrawState.fColor; + } + break; + case GrGLProgram::ProgramDesc::kUniform_ColorType: + if (fProgramData->fColor != fCurrDrawState.fColor) { + // OpenGL ES only supports the float varities of glVertexAttrib + float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor); + GrAssert(GrGLProgram::kUnusedUniform != + fProgramData->fUniLocations.fColorUni); + GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorUni, 1, c)); + fProgramData->fColor = fCurrDrawState.fColor; + } + break; + case GrGLProgram::ProgramDesc::kNone_ColorType: + GrAssert(0xffffffff == fCurrDrawState.fColor); + break; + default: + GrCrash("Unknown color type."); + } + } + if (fProgramData->fUniLocations.fColorFilterUni + != GrGLProgram::kUnusedUniform + && fProgramData->fColorFilterColor + != fCurrDrawState.fColorFilterColor) { + float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColorFilterColor); + GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorFilterUni, 1, c)); + fProgramData->fColorFilterColor = fCurrDrawState.fColorFilterColor; + } } + bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) { if (!flushGLStateCommon(type)) { return false; @@ -281,33 +473,17 @@ bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) { if (fDirtyFlags.fRenderTargetChanged) { // our coords are in pixel space and the GL matrices map to NDC // so if the viewport changed, our matrix is now wrong. -#if ATTRIBUTE_MATRIX fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix(); -#else // we assume all shader matrices may be wrong after viewport changes fProgramCache->invalidateViewMatrices(); -#endif - } - - if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) { - // invalidate the immediate mode color - fHWDrawState.fColor = GrColor_ILLEGAL; - } else { - if (fHWDrawState.fColor != fCurrDrawState.fColor) { - // OpenGL ES only supports the float varities of glVertexAttrib - float c[] = { - GrColorUnpackR(fCurrDrawState.fColor) / 255.f, - GrColorUnpackG(fCurrDrawState.fColor) / 255.f, - GrColorUnpackB(fCurrDrawState.fColor) / 255.f, - GrColorUnpackA(fCurrDrawState.fColor) / 255.f - }; - GR_GL(VertexAttrib4fv(COL_ATTR_LOCATION, c)); - fHWDrawState.fColor = fCurrDrawState.fColor; - } } buildProgram(type); - fProgramData = fProgramCache->getProgramData(fCurrentProgram, this); + fProgramData = fProgramCache->getProgramData(fCurrentProgram); + if (NULL == fProgramData) { + GrAssert(!"Failed to create program!"); + return false; + } if (fHWProgramID != fProgramData->fProgramID) { GR_GL(UseProgram(fProgramData->fProgramID)); @@ -318,41 +494,29 @@ bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) { return false; } -#if ATTRIBUTE_MATRIX - GrMatrix& currViewMatrix = fHWDrawState.fViewMatrix; -#else - GrMatrix& currViewMatrix = fProgramData->fViewMatrix; -#endif + this->flushColor(); - if (currViewMatrix != fCurrDrawState.fViewMatrix) { + GrMatrix* currViewMatrix; + if (GrGLProgram::kSetAsAttribute == + fProgramData->fUniLocations.fViewMatrixUni) { + currViewMatrix = &fHWDrawState.fViewMatrix; + } else { + currViewMatrix = &fProgramData->fViewMatrix; + } + + if (*currViewMatrix != fCurrDrawState.fViewMatrix) { flushViewMatrix(); - currViewMatrix = fCurrDrawState.fViewMatrix; + *currViewMatrix = fCurrDrawState.fViewMatrix; } for (int s = 0; s < kNumStages; ++s) { - GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; - if (NULL != texture) { - if (-1 != fProgramData->fUniLocations.fStages[s].fTextureMatrixUni && - (((1 << s) & fDirtyFlags.fTextureChangedMask) || - getHWSamplerMatrix(s) != getSamplerMatrix(s))) { - flushTextureMatrix(s); - recordHWSamplerMatrix(s, getSamplerMatrix(s)); - } - } + this->flushTextureMatrix(s); - const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s]; - if (-1 != fProgramData->fUniLocations.fStages[s].fRadial2Uni && - (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() || - fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() || - fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) { + this->flushRadial2(s); - flushRadial2(s); - - fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1(); - fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0(); - fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot(); - } + this->flushTexelSize(s); } + this->flushEdgeAAData(); resetDirtyFlags(); return true; } @@ -413,42 +577,43 @@ void GrGpuGLShaders::setupGeometry(int* startVertex, fGeometrySrc.fVertexLayout))); if (posAndTexChange) { - GR_GL(VertexAttribPointer(POS_ATTR_LOCATION, 2, scalarType, - false, newStride, (GrGLvoid*)vertexOffset)); + int idx = GrGLProgram::PositionAttributeIdx(); + GR_GL(VertexAttribPointer(idx, 2, scalarType, false, newStride, + (GrGLvoid*)vertexOffset)); fHWGeometryState.fVertexOffset = vertexOffset; } for (int t = 0; t < kMaxTexCoords; ++t) { if (newTexCoordOffsets[t] > 0) { GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]); + int idx = GrGLProgram::TexCoordAttributeIdx(t); if (oldTexCoordOffsets[t] <= 0) { - GR_GL(EnableVertexAttribArray(TEX_ATTR_LOCATION(t))); - GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType, - texCoordNorm, newStride, texCoordOffset)); + GR_GL(EnableVertexAttribArray(idx)); + GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm, + newStride, texCoordOffset)); } else if (posAndTexChange || newTexCoordOffsets[t] != oldTexCoordOffsets[t]) { - GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType, - texCoordNorm, newStride, texCoordOffset)); + GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm, + newStride, texCoordOffset)); } } else if (oldTexCoordOffsets[t] > 0) { - GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION(t))); + GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t))); } } if (newColorOffset > 0) { GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset); + int idx = GrGLProgram::ColorAttributeIdx(); if (oldColorOffset <= 0) { - GR_GL(EnableVertexAttribArray(COL_ATTR_LOCATION)); - GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4, - GR_GL_UNSIGNED_BYTE, + GR_GL(EnableVertexAttribArray(idx)); + GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE, true, newStride, colorOffset)); } else if (allOffsetsChange || newColorOffset != oldColorOffset) { - GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4, - GR_GL_UNSIGNED_BYTE, + GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE, true, newStride, colorOffset)); } } else if (oldColorOffset > 0) { - GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION)); + GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx())); } fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout; @@ -456,24 +621,40 @@ void GrGpuGLShaders::setupGeometry(int* startVertex, } void GrGpuGLShaders::buildProgram(GrPrimitiveType type) { + GrGLProgram::ProgramDesc& desc = fCurrentProgram.fProgramDesc; + // Must initialize all fields or cache will have false negatives! - fCurrentProgram.fProgramDesc.fVertexLayout = fGeometrySrc.fVertexLayout; + desc.fVertexLayout = fGeometrySrc.fVertexLayout; + + desc.fEmitsPointSize = kPoints_PrimitiveType == type; + + bool requiresAttributeColors = desc.fVertexLayout & kColor_VertexLayoutBit; + // fColorType records how colors are specified for the program. Strip + // the bit from the layout to avoid false negatives when searching for an + // existing program in the cache. + desc.fVertexLayout &= ~(kColor_VertexLayoutBit); - fCurrentProgram.fProgramDesc.fOptFlags = 0; - if (kPoints_PrimitiveType != type) { - fCurrentProgram.fProgramDesc.fOptFlags |= GrGLProgram::ProgramDesc::kNotPoints_OptFlagBit; - } #if GR_AGGRESSIVE_SHADER_OPTS - if (!(fCurrentProgram.fProgramDesc.fVertexLayout & kColor_VertexLayoutBit) && - (0xffffffff == fCurrDrawState.fColor)) { - fCurrentProgram.fProgramDesc.fOptFlags |= GrGLProgram::ProgramDesc::kVertexColorAllOnes_OptFlagBit; - } + if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) { + desc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType; + } else #endif +#if GR_GL_NO_CONSTANT_ATTRIBUTES + if (!requiresAttributeColors) { + desc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType; + } else +#endif + { + if (requiresAttributeColors) {} // suppress unused var warning + desc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType; + } + + desc.fUsesEdgeAA = fCurrDrawState.fFlagBits & kEdgeAA_StateBit; for (int s = 0; s < kNumStages; ++s) { - GrGLProgram::ProgramDesc::StageDesc& stage = fCurrentProgram.fProgramDesc.fStages[s]; + GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s]; - stage.fEnabled = VertexUsesStage(s, fGeometrySrc.fVertexLayout); + stage.fEnabled = this->isStageEnabled(s); if (stage.fEnabled) { GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; @@ -488,21 +669,36 @@ void GrGpuGLShaders::buildProgram(GrPrimitiveType type) { stage.fOptFlags = 0; } switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) { - case GrSamplerState::kNormal_SampleMode: - stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping; - break; - case GrSamplerState::kRadial_SampleMode: - stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping; - break; - case GrSamplerState::kRadial2_SampleMode: - stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping; - break; - case GrSamplerState::kSweep_SampleMode: - stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping; - break; - default: - GrAssert(!"Unexpected sample mode!"); - break; + case GrSamplerState::kNormal_SampleMode: + stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping; + break; + case GrSamplerState::kRadial_SampleMode: + stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping; + break; + case GrSamplerState::kRadial2_SampleMode: + stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping; + break; + case GrSamplerState::kSweep_SampleMode: + stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping; + break; + default: + GrCrash("Unexpected sample mode!"); + break; + } + + switch (fCurrDrawState.fSamplerStates[s].getFilter()) { + // these both can use a regular texture2D() + case GrSamplerState::kNearest_Filter: + case GrSamplerState::kBilinear_Filter: + stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode; + break; + // performs 4 texture2D()s + case GrSamplerState::k4x4Downsample_Filter: + stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode; + break; + default: + GrCrash("Unexpected filter!"); + break; } if (GrPixelConfigIsAlphaOnly(texture->config())) { @@ -524,6 +720,7 @@ void GrGpuGLShaders::buildProgram(GrPrimitiveType type) { fCurrentProgram.fStageEffects[s] = NULL; } } + desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode; } diff --git a/gpu/src/GrGpuGLShaders.h b/gpu/src/GrGpuGLShaders.h index ee29533..bb3024f 100644 --- a/gpu/src/GrGpuGLShaders.h +++ b/gpu/src/GrGpuGLShaders.h @@ -51,12 +51,21 @@ private: // sets the texture matrix uniform for currently bound program void flushTextureMatrix(int stage); + // sets the color specified by GrDrawTarget::setColor() + void flushColor(); + // sets the MVP matrix uniform for currently bound program void flushViewMatrix(); // flushes the parameters to two point radial gradient void flushRadial2(int stage); + // flushes the normalized texel size + void flushTexelSize(int stage); + + // flushes the edges for edge AA + void flushEdgeAAData(); + static void DeleteProgram(GrGLProgram::CachedData* programData); void ProgramUnitTest(); diff --git a/gpu/src/GrGpuGLShaders2.cpp b/gpu/src/GrGpuGLShaders2.cpp deleted file mode 100644 index 4deecd4..0000000 --- a/gpu/src/GrGpuGLShaders2.cpp +++ /dev/null @@ -1,1416 +0,0 @@ -/* - Copyright 2011 Google Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - - -#include "GrGLConfig.h" - -#include "GrGpuGLShaders2.h" -#include "GrGpuVertex.h" -#include "GrMemory.h" -#include "GrStringBuilder.h" - - -#define ATTRIBUTE_MATRIX 0 - -#define PRINT_SHADERS 0 - -#define SKIP_CACHE_CHECK true - -#define POS_ATTR_LOCATION 0 -#define TEX_ATTR_LOCATION(X) (1 + X) -#define COL_ATTR_LOCATION (2 + GrDrawTarget::kMaxTexCoords) -#if ATTRIBUTE_MATRIX -#define VIEWMAT_ATTR_LOCATION (3 + GrDrawTarget::kMaxTexCoords) -#define TEXMAT_ATTR_LOCATION(X) (6 + GrDrawTarget::kMaxTexCoords + 3 * (X)) -#define BOGUS_MATRIX_UNI_LOCATION 1000 -#endif - -#define GR_UINT32_MAX static_cast<uint32_t>(-1) - -namespace { - -const char* GrPrecision() { - if (GR_GL_SUPPORT_ES2) { - return "mediump"; - } else { - return ""; - } -} - -const char* GrShaderPrecision() { - if (GR_GL_SUPPORT_ES2) { - return "precision mediump float;\n"; - } else { - return ""; - } -} - -} // namespace - -struct GrGpuGLShaders2::StageUniLocations { - GrGLint fTextureMatrixUni; - GrGLint fSamplerUni; - GrGLint fRadial2Uni; -}; - -struct GrGpuGLShaders2::UniLocations { - GrGLint fViewMatrixUni; - StageUniLocations fStages[kNumStages]; -}; - -// Records per-program information -// we can specify the attribute locations so that they are constant -// across our shaders. But the driver determines the uniform locations -// at link time. We don't need to remember the sampler uniform location -// because we will bind a texture slot to it and never change it -// Uniforms are program-local so we can't rely on fHWState to hold the -// previous uniform state after a program change. -struct GrGpuGLShaders2::Program { - // IDs - GrGLuint fVShaderID; - GrGLuint fFShaderID; - GrGLuint fProgramID; - - // shader uniform locations (-1 if shader doesn't use them) - UniLocations fUniLocations; - - // these reflect the current values of uniforms - // (GL uniform values travel with program) - GrMatrix fViewMatrix; - GrMatrix fTextureMatrices[kNumStages]; - GrScalar fRadial2CenterX1[kNumStages]; - GrScalar fRadial2Radius0[kNumStages]; - bool fRadial2PosRoot[kNumStages]; - -}; - -// must be tightly packed -struct GrGpuGLShaders2::StageDesc { - enum OptFlagBits { - kNoPerspective_OptFlagBit = 0x1, - kIdentityMatrix_OptFlagBit = 0x2, - }; - unsigned fOptFlags : 8; - - unsigned fEnabled : 8; - - enum Modulation { - kColor_Modulation, - kAlpha_Modulation, - } fModulation : 8; - - enum CoordMapping { - kIdentity_CoordMapping, - kRadialGradient_CoordMapping, - kSweepGradient_CoordMapping, - kRadial2Gradient_CoordMapping, - } fCoordMapping : 8; -}; - -// must be tightly packed -struct GrGpuGLShaders2::ProgramDesc { - GrVertexLayout fVertexLayout; - GR_STATIC_ASSERT(2 == sizeof(GrVertexLayout)); // pack with next field - - enum { - kNotPoints_OptFlagBit = 0x1, - kVertexColorAllOnes_OptFlagBit = 0x2, - }; - // we're assuming optflags and layout pack into 32 bits - // VS 2010 seems to require short rather than just unsigned - // for this to pack - unsigned short fOptFlags : 16; - - StageDesc fStages[kNumStages]; - - bool operator == (const ProgramDesc& desc) const { - // keep 4-byte aligned and tightly packed - GR_STATIC_ASSERT(4 == sizeof(StageDesc)); - GR_STATIC_ASSERT(2 + 2 + 4 * kNumStages == sizeof(ProgramDesc)); - return 0 == memcmp(this, &desc, sizeof(ProgramDesc)); - } -}; - -#include "GrTHashCache.h" - -class GrGpuGLShaders2::ProgramCache : public ::GrNoncopyable { -private: - struct Entry; - class HashKey { - public: - HashKey(); - HashKey(const ProgramDesc& desc); - static const HashKey& GetKey(const Entry&); - static bool EQ(const Entry&, const HashKey&); - static bool LT(const Entry&, const HashKey&); - bool operator <(const HashKey& key) const; - bool operator ==(const HashKey& key) const; - uint32_t getHash() const; - private: - ProgramDesc fDesc; - uint32_t fHash; - }; - - struct Entry { - Program fProgram; - HashKey fKey; - uint32_t fLRUStamp; - }; - - // if hash bits is changed, need to change hash function - GrTHashTable<Entry, HashKey, 8> fHashCache; - - static const int MAX_ENTRIES = 16; - Entry fEntries[MAX_ENTRIES]; - int fCount; - uint32_t fCurrLRUStamp; - -public: - ProgramCache() { - fCount = 0; - fCurrLRUStamp = 0; - } - - ~ProgramCache() { - for (int i = 0; i < fCount; ++i) { - GrGpuGLShaders2::DeleteProgram(&fEntries[i].fProgram); - } - } - - void abandon() { - fCount = 0; - } - - void invalidateViewMatrices() { - for (int i = 0; i < fCount; ++i) { - // set to illegal matrix - fEntries[i].fProgram.fViewMatrix = GrMatrix::InvalidMatrix(); - } - } - - Program* getProgram(const ProgramDesc& desc) { - HashKey key(desc); - Entry* entry = fHashCache.find(key); - if (NULL == entry) { - if (fCount < MAX_ENTRIES) { - entry = fEntries + fCount; - ++fCount; - } else { - GrAssert(MAX_ENTRIES == fCount); - entry = fEntries; - for (int i = 1; i < MAX_ENTRIES; ++i) { - if (fEntries[i].fLRUStamp < entry->fLRUStamp) { - entry = fEntries + i; - } - } - fHashCache.remove(entry->fKey, entry); - GrGpuGLShaders2::DeleteProgram(&entry->fProgram); - } - entry->fKey = key; - GrGpuGLShaders2::GenProgram(desc, &entry->fProgram); - fHashCache.insert(entry->fKey, entry); - } - - entry->fLRUStamp = fCurrLRUStamp; - if (GR_UINT32_MAX == fCurrLRUStamp) { - // wrap around! just trash our LRU, one time hit. - for (int i = 0; i < fCount; ++i) { - fEntries[i].fLRUStamp = 0; - } - } - ++fCurrLRUStamp; - return &entry->fProgram; - } -}; - -GrGpuGLShaders2::ProgramCache::HashKey::HashKey() { -} - -static uint32_t ror(uint32_t x) { - return (x >> 8) | (x << 24); -} - -static uint32_t rol(uint32_t x) { - return (x << 8) | (x >> 24); -} - -GrGpuGLShaders2::ProgramCache::HashKey::HashKey(const ProgramDesc& desc) { - fDesc = desc; - // if you change the size of the desc, need to update the hash function - GR_STATIC_ASSERT(12 == sizeof(ProgramDesc)); - - uint32_t* d = GrTCast<uint32_t*>(&fDesc); - fHash = d[0] ^ ror(d[1]) ^ rol(d[2]); -} - -bool GrGpuGLShaders2::ProgramCache::HashKey::EQ(const Entry& entry, - const HashKey& key) { - return entry.fKey == key; -} - -bool GrGpuGLShaders2::ProgramCache::HashKey::LT(const Entry& entry, - const HashKey& key) { - return entry.fKey < key; -} - -bool GrGpuGLShaders2::ProgramCache::HashKey::operator ==(const HashKey& key) const { - return fDesc == key.fDesc; -} - -bool GrGpuGLShaders2::ProgramCache::HashKey::operator <(const HashKey& key) const { - return memcmp(&fDesc, &key.fDesc, sizeof(HashKey)) < 0; -} - -uint32_t GrGpuGLShaders2::ProgramCache::HashKey::getHash() const { - return fHash; -} - -struct GrGpuGLShaders2::ShaderCodeSegments { - GrSStringBuilder<256> fVSUnis; - GrSStringBuilder<256> fVSAttrs; - GrSStringBuilder<256> fVaryings; - GrSStringBuilder<256> fFSUnis; - GrSStringBuilder<512> fVSCode; - GrSStringBuilder<512> fFSCode; -}; -// for variable names etc -typedef GrSStringBuilder<16> GrTokenString; - -#if ATTRIBUTE_MATRIX - #define VIEW_MATRIX_NAME "aViewM" -#else - #define VIEW_MATRIX_NAME "uViewM" -#endif - -#define POS_ATTR_NAME "aPosition" -#define COL_ATTR_NAME "aColor" - -static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) { - *s = "aTexCoord"; - s->appendInt(coordIdx); -} - -static inline const char* float_vector_type(int count) { - static const char* FLOAT_VECS[] = {"ERROR", "float", "vec2", "vec3", "vec4"}; - GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(FLOAT_VECS)); - return FLOAT_VECS[count]; -} - -static inline const char* vector_homog_coord(int count) { - static const char* HOMOGS[] = {"ERROR", "", ".y", ".z", ".w"}; - GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(HOMOGS)); - return HOMOGS[count]; -} - -static inline const char* vector_nonhomog_coords(int count) { - static const char* NONHOMOGS[] = {"ERROR", "", ".x", ".xy", ".xyz"}; - GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(NONHOMOGS)); - return NONHOMOGS[count]; -} - -static inline const char* vector_all_coords(int count) { - static const char* ALL[] = {"ERROR", "", ".xy", ".xyz", ".xyzw"}; - GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ALL)); - return ALL[count]; -} - -static void tex_matrix_name(int stage, GrStringBuilder* s) { -#if ATTRIBUTE_MATRIX - *s = "aTexM"; -#else - *s = "uTexM"; -#endif - s->appendInt(stage); -} - -static void sampler_name(int stage, GrStringBuilder* s) { - *s = "uSampler"; - s->appendInt(stage); -} - -static void stage_varying_name(int stage, GrStringBuilder* s) { - *s = "vStage"; - s->appendInt(stage); -} - -static void radial2_param_name(int stage, GrStringBuilder* s) { - *s = "uRadial2Params"; - s->appendInt(stage); -} - -static void radial2_varying_name(int stage, GrStringBuilder* s) { - *s = "vB"; - s->appendInt(stage); -} - -#include "GrRandom.h" - -void GrGpuGLShaders2::ProgramUnitTest() { - static const int PROG_OPTS[] = { - 0, - ProgramDesc::kNotPoints_OptFlagBit, - ProgramDesc::kVertexColorAllOnes_OptFlagBit, - ProgramDesc::kNotPoints_OptFlagBit | ProgramDesc::kVertexColorAllOnes_OptFlagBit - }; - static const int STAGE_OPTS[] = { - 0, - StageDesc::kNoPerspective_OptFlagBit, - StageDesc::kIdentity_CoordMapping - }; - static const int STAGE_MODULATES[] = { - StageDesc::kColor_Modulation, - StageDesc::kAlpha_Modulation - }; - static const int STAGE_COORD_MAPPINGS[] = { - StageDesc::kIdentity_CoordMapping, - StageDesc::kRadialGradient_CoordMapping, - StageDesc::kSweepGradient_CoordMapping, - StageDesc::kRadial2Gradient_CoordMapping - }; - ProgramDesc pdesc; - memset(&pdesc, 0, sizeof(pdesc)); - - static const int NUM_TESTS = 512; - - // GrRandoms nextU() values have patterns in the low bits - // So using nextU() % array_count might never take some values. - GrRandom random; - for (int t = 0; t < NUM_TESTS; ++t) { - - pdesc.fVertexLayout = 0; - for (int s = 0; s < kNumStages; ++s) { - // enable the stage? - if (random.nextF() > .5f) { - // use separate tex coords? - if (random.nextF() > .5f) { - int t = (int)(random.nextF() * kMaxTexCoords); - pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t); - } else { - pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s); - } - } - // use text-formatted verts? - if (random.nextF() > .5f) { - pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit; - } - } - - int x = (int)(random.nextF() * GR_ARRAY_COUNT(PROG_OPTS)); - pdesc.fOptFlags = PROG_OPTS[x]; - for (int s = 0; s < kNumStages; ++s) { - pdesc.fStages[s].fEnabled = VertexUsesStage(s, pdesc.fVertexLayout); - x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS)); - pdesc.fStages[s].fOptFlags = STAGE_OPTS[x]; - x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES)); - pdesc.fStages[s].fModulation = (StageDesc::Modulation) STAGE_MODULATES[x]; - x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS)); - pdesc.fStages[s].fCoordMapping = (StageDesc::CoordMapping) STAGE_COORD_MAPPINGS[x]; - } - Program program; - GenProgram(pdesc, &program); - DeleteProgram(&program); - } -} - -void GrGpuGLShaders2::GenStageCode(int stageNum, - const StageDesc& desc, - const char* fsInColor, // NULL means no incoming color - const char* fsOutColor, - const char* vsInCoord, - ShaderCodeSegments* segments, - StageUniLocations* locations) { - - GrAssert(stageNum >= 0 && stageNum <= 9); - - GrTokenString varyingName; - stage_varying_name(stageNum, &varyingName); - - // First decide how many coords are needed to access the texture - // Right now it's always 2 but we could start using 1D textures for - // gradients. - static const int coordDims = 2; - int varyingDims; - /// Vertex Shader Stuff - - // decide whether we need a matrix to transform texture coords - // and whether the varying needs a perspective coord. - GrTokenString texMName; - tex_matrix_name(stageNum, &texMName); - if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) { - varyingDims = coordDims; - } else { - #if ATTRIBUTE_MATRIX - segments->fVSAttrs += "attribute mat3 "; - segments->fVSAttrs += texMName; - segments->fVSAttrs += ";\n"; - #else - segments->fVSUnis += "uniform mat3 "; - segments->fVSUnis += texMName; - segments->fVSUnis += ";\n"; - locations->fTextureMatrixUni = 1; - #endif - if (desc.fOptFlags & StageDesc::kNoPerspective_OptFlagBit) { - varyingDims = coordDims; - } else { - varyingDims = coordDims + 1; - } - } - - GrTokenString samplerName; - sampler_name(stageNum, &samplerName); - segments->fFSUnis += "uniform sampler2D "; - segments->fFSUnis += samplerName; - segments->fFSUnis += ";\n"; - locations->fSamplerUni = 1; - - segments->fVaryings += "varying "; - segments->fVaryings += float_vector_type(varyingDims); - segments->fVaryings += " "; - segments->fVaryings += varyingName; - segments->fVaryings += ";\n"; - - if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) { - GrAssert(varyingDims == coordDims); - segments->fVSCode += "\t"; - segments->fVSCode += varyingName; - segments->fVSCode += " = "; - segments->fVSCode += vsInCoord; - segments->fVSCode += ";\n"; - } else { - segments->fVSCode += "\t"; - segments->fVSCode += varyingName; - segments->fVSCode += " = ("; - segments->fVSCode += texMName; - segments->fVSCode += " * vec3("; - segments->fVSCode += vsInCoord; - segments->fVSCode += ", 1))"; - segments->fVSCode += vector_all_coords(varyingDims); - segments->fVSCode += ";\n"; - } - - GrTokenString radial2ParamsName; - radial2_param_name(stageNum, &radial2ParamsName); - // for radial grads without perspective we can pass the linear - // part of the quadratic as a varying. - GrTokenString radial2VaryingName; - radial2_varying_name(stageNum, &radial2VaryingName); - - if (StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping) { - - segments->fVSUnis += "uniform "; - segments->fVSUnis += GrPrecision(); - segments->fVSUnis += " float "; - segments->fVSUnis += radial2ParamsName; - segments->fVSUnis += "[6];\n"; - - segments->fFSUnis += "uniform "; - segments->fFSUnis += GrPrecision(); - segments->fFSUnis += " float "; - segments->fFSUnis += radial2ParamsName; - segments->fFSUnis += "[6];\n"; - locations->fRadial2Uni = 1; - - // if there is perspective we don't interpolate this - if (varyingDims == coordDims) { - GrAssert(2 == coordDims); - segments->fVaryings += "varying float "; - segments->fVaryings += radial2VaryingName; - segments->fVaryings += ";\n"; - - segments->fVSCode += "\t"; - segments->fVSCode += radial2VaryingName; - segments->fVSCode += " = 2.0 * ("; - segments->fVSCode += radial2ParamsName; - segments->fVSCode += "[2] * "; - segments->fVSCode += varyingName; - segments->fVSCode += ".x "; - segments->fVSCode += " - "; - segments->fVSCode += radial2ParamsName; - segments->fVSCode += "[3]);\n"; - } - } - - /// Fragment Shader Stuff - GrTokenString fsCoordName; - // function used to access the shader, may be made projective - GrTokenString texFunc("texture2D"); - if (desc.fOptFlags & (StageDesc::kIdentityMatrix_OptFlagBit | - StageDesc::kNoPerspective_OptFlagBit)) { - GrAssert(varyingDims == coordDims); - fsCoordName = varyingName; - } else { - // if we have to do some non-matrix op on the varyings to get - // our final tex coords then when in perspective we have to - // do an explicit divide - if (StageDesc::kIdentity_CoordMapping == desc.fCoordMapping) { - texFunc += "Proj"; - fsCoordName = varyingName; - } else { - fsCoordName = "tCoord"; - fsCoordName.appendInt(stageNum); - - segments->fFSCode += "\t"; - segments->fFSCode += float_vector_type(coordDims); - segments->fFSCode += " "; - segments->fFSCode += fsCoordName; - segments->fFSCode += " = "; - segments->fFSCode += varyingName; - segments->fFSCode += vector_nonhomog_coords(varyingDims); - segments->fFSCode += " / "; - segments->fFSCode += varyingName; - segments->fFSCode += vector_homog_coord(varyingDims); - segments->fFSCode += ";\n"; - } - } - - GrSStringBuilder<96> sampleCoords; - switch (desc.fCoordMapping) { - case StageDesc::kIdentity_CoordMapping: - sampleCoords = fsCoordName; - break; - case StageDesc::kSweepGradient_CoordMapping: - sampleCoords = "vec2(atan(-"; - sampleCoords += fsCoordName; - sampleCoords += ".y, -"; - sampleCoords += fsCoordName; - sampleCoords += ".x)*0.1591549430918 + 0.5, 0.5)"; - break; - case StageDesc::kRadialGradient_CoordMapping: - sampleCoords = "vec2(length("; - sampleCoords += fsCoordName; - sampleCoords += ".xy), 0.5)"; - break; - case StageDesc::kRadial2Gradient_CoordMapping: { - GrTokenString cName = "c"; - GrTokenString ac4Name = "ac4"; - GrTokenString rootName = "root"; - - cName.appendInt(stageNum); - ac4Name.appendInt(stageNum); - rootName.appendInt(stageNum); - - GrTokenString bVar; - if (coordDims == varyingDims) { - bVar = radial2VaryingName; - GrAssert(2 == varyingDims); - } else { - GrAssert(3 == varyingDims); - bVar = "b"; - bVar.appendInt(stageNum); - segments->fFSCode += "\tfloat "; - segments->fFSCode += bVar; - segments->fFSCode += " = 2.0 * ("; - segments->fFSCode += radial2ParamsName; - segments->fFSCode += "[2] * "; - segments->fFSCode += fsCoordName; - segments->fFSCode += ".x "; - segments->fFSCode += " - "; - segments->fFSCode += radial2ParamsName; - segments->fFSCode += "[3]);\n"; - } - - segments->fFSCode += "\tfloat "; - segments->fFSCode += cName; - segments->fFSCode += " = dot("; - segments->fFSCode += fsCoordName; - segments->fFSCode += ", "; - segments->fFSCode += fsCoordName; - segments->fFSCode += ") + "; - segments->fFSCode += " - "; - segments->fFSCode += radial2ParamsName; - segments->fFSCode += "[4];\n"; - - segments->fFSCode += "\tfloat "; - segments->fFSCode += ac4Name; - segments->fFSCode += " = "; - segments->fFSCode += radial2ParamsName; - segments->fFSCode += "[0] * 4.0 * "; - segments->fFSCode += cName; - segments->fFSCode += ";\n"; - - segments->fFSCode += "\tfloat "; - segments->fFSCode += rootName; - segments->fFSCode += " = sqrt(abs("; - segments->fFSCode += bVar; - segments->fFSCode += " * "; - segments->fFSCode += bVar; - segments->fFSCode += " - "; - segments->fFSCode += ac4Name; - segments->fFSCode += "));\n"; - - sampleCoords = "vec2((-"; - sampleCoords += bVar; - sampleCoords += " + "; - sampleCoords += radial2ParamsName; - sampleCoords += "[5] * "; - sampleCoords += rootName; - sampleCoords += ") * "; - sampleCoords += radial2ParamsName; - sampleCoords += "[1], 0.5)\n"; - break;} - }; - - segments->fFSCode += "\t"; - segments->fFSCode += fsOutColor; - segments->fFSCode += " = "; - if (NULL != fsInColor) { - segments->fFSCode += fsInColor; - segments->fFSCode += " * "; - } - segments->fFSCode += texFunc; - segments->fFSCode += "("; - segments->fFSCode += samplerName; - segments->fFSCode += ", "; - segments->fFSCode += sampleCoords; - segments->fFSCode += ")"; - if (desc.fModulation == StageDesc::kAlpha_Modulation) { - segments->fFSCode += ".aaaa"; - } - segments->fFSCode += ";\n"; - -} - -void GrGpuGLShaders2::GenProgram(const ProgramDesc& desc, - Program* program) { - - ShaderCodeSegments segments; - const uint32_t& layout = desc.fVertexLayout; - - memset(&program->fUniLocations, 0, sizeof(UniLocations)); - - bool haveColor = !(ProgramDesc::kVertexColorAllOnes_OptFlagBit & - desc.fOptFlags); - -#if ATTRIBUTE_MATRIX - segments.fVSAttrs = "attribute mat3 " VIEW_MATRIX_NAME ";\n"; -#else - segments.fVSUnis = "uniform mat3 " VIEW_MATRIX_NAME ";\n"; - segments.fVSAttrs = ""; -#endif - segments.fVSAttrs += "attribute vec2 " POS_ATTR_NAME ";\n"; - if (haveColor) { - segments.fVSAttrs += "attribute vec4 " COL_ATTR_NAME ";\n"; - segments.fVaryings = "varying vec4 vColor;\n"; - } else { - segments.fVaryings = ""; - } - - segments.fVSCode = "void main() {\n" - "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3(" POS_ATTR_NAME ", 1);\n" - "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n"; - if (haveColor) { - segments.fVSCode += "\tvColor = " COL_ATTR_NAME ";\n"; - } - - if (!(desc.fOptFlags & ProgramDesc::kNotPoints_OptFlagBit)){ - segments.fVSCode += "\tgl_PointSize = 1.0;\n"; - } - segments.fFSCode = "void main() {\n"; - - // add texture coordinates that are used to the list of vertex attr decls - GrTokenString texCoordAttrs[kMaxTexCoords]; - for (int t = 0; t < kMaxTexCoords; ++t) { - if (VertexUsesTexCoordIdx(t, layout)) { - tex_attr_name(t, texCoordAttrs + t); - - segments.fVSAttrs += "attribute vec2 "; - segments.fVSAttrs += texCoordAttrs[t]; - segments.fVSAttrs += ";\n"; - } - } - - // for each enabled stage figure out what the input coordinates are - // and count the number of stages in use. - const char* stageInCoords[kNumStages]; - int numActiveStages = 0; - - for (int s = 0; s < kNumStages; ++s) { - if (desc.fStages[s].fEnabled) { - if (StagePosAsTexCoordVertexLayoutBit(s) & layout) { - stageInCoords[s] = POS_ATTR_NAME; - } else { - int tcIdx = VertexTexCoordsForStage(s, layout); - // we better have input tex coordinates if stage is enabled. - GrAssert(tcIdx >= 0); - GrAssert(texCoordAttrs[tcIdx].length()); - stageInCoords[s] = texCoordAttrs[tcIdx].cstr(); - } - ++numActiveStages; - } - } - - GrTokenString inColor = "vColor"; - - // if we have active stages string them together, feeding the output color - // of each to the next and generating code for each stage. - if (numActiveStages) { - int currActiveStage = 0; - for (int s = 0; s < kNumStages; ++s) { - if (desc.fStages[s].fEnabled) { - GrTokenString outColor; - if (currActiveStage < (numActiveStages - 1)) { - outColor = "color"; - outColor.appendInt(currActiveStage); - segments.fFSCode += "\tvec4 "; - segments.fFSCode += outColor; - segments.fFSCode += ";\n"; - } else { - outColor = "gl_FragColor"; - } - GenStageCode(s, - desc.fStages[s], - haveColor ? inColor.cstr() : NULL, - outColor.cstr(), - stageInCoords[s], - &segments, - &program->fUniLocations.fStages[s]); - ++currActiveStage; - inColor = outColor; - haveColor = true; - } - } - } else { - segments.fFSCode += "\tgl_FragColor = "; - if (haveColor) { - segments.fFSCode += inColor; - } else { - segments.fFSCode += "vec4(1,1,1,1)"; - } - segments.fFSCode += ";\n"; - } - segments.fFSCode += "}\n"; - segments.fVSCode += "}\n"; - - - const char* strings[4]; - int lengths[4]; - int stringCnt = 0; - - if (segments.fVSUnis.length()) { - strings[stringCnt] = segments.fVSUnis.cstr(); - lengths[stringCnt] = segments.fVSUnis.length(); - ++stringCnt; - } - if (segments.fVSAttrs.length()) { - strings[stringCnt] = segments.fVSAttrs.cstr(); - lengths[stringCnt] = segments.fVSAttrs.length(); - ++stringCnt; - } - if (segments.fVaryings.length()) { - strings[stringCnt] = segments.fVaryings.cstr(); - lengths[stringCnt] = segments.fVaryings.length(); - ++stringCnt; - } - - GrAssert(segments.fVSCode.length()); - strings[stringCnt] = segments.fVSCode.cstr(); - lengths[stringCnt] = segments.fVSCode.length(); - ++stringCnt; - -#if PRINT_SHADERS - GrPrintf("%s%s%s%s\n", - segments.fVSUnis.cstr(), - segments.fVSAttrs.cstr(), - segments.fVaryings.cstr(), - segments.fVSCode.cstr()); -#endif - program->fVShaderID = CompileShader(GR_GL_VERTEX_SHADER, - stringCnt, - strings, - lengths); - - stringCnt = 0; - - if (strlen(GrShaderPrecision()) > 1) { - strings[stringCnt] = GrShaderPrecision(); - lengths[stringCnt] = strlen(GrShaderPrecision()); - ++stringCnt; - } - if (segments.fFSUnis.length()) { - strings[stringCnt] = segments.fFSUnis.cstr(); - lengths[stringCnt] = segments.fFSUnis.length(); - ++stringCnt; - } - if (segments.fVaryings.length()) { - strings[stringCnt] = segments.fVaryings.cstr(); - lengths[stringCnt] = segments.fVaryings.length(); - ++stringCnt; - } - - GrAssert(segments.fFSCode.length()); - strings[stringCnt] = segments.fFSCode.cstr(); - lengths[stringCnt] = segments.fFSCode.length(); - ++stringCnt; - -#if PRINT_SHADERS - GrPrintf("%s%s%s%s\n", - GrShaderPrecision(), - segments.fFSUnis.cstr(), - segments.fVaryings.cstr(), - segments.fFSCode.cstr()); -#endif - program->fFShaderID = CompileShader(GR_GL_FRAGMENT_SHADER, - stringCnt, - strings, - lengths); - - program->fProgramID = GR_GL(CreateProgram()); - const GrGLint& progID = program->fProgramID; - - GR_GL(AttachShader(progID, program->fVShaderID)); - GR_GL(AttachShader(progID, program->fFShaderID)); - - // Bind the attrib locations to same values for all shaders - GR_GL(BindAttribLocation(progID, POS_ATTR_LOCATION, POS_ATTR_NAME)); - for (int t = 0; t < kMaxTexCoords; ++t) { - if (texCoordAttrs[t].length()) { - GR_GL(BindAttribLocation(progID, - TEX_ATTR_LOCATION(t), - texCoordAttrs[t].cstr())); - } - } - -#if ATTRIBUTE_MATRIX - // set unis to a bogus value so that checks against -1 before - // flushing will pass. - GR_GL(BindAttribLocation(progID, - VIEWMAT_ATTR_LOCATION, - VIEW_MATRIX_NAME)); - - program->fUniLocations.fViewMatrixUni = BOGUS_MATRIX_UNI_LOCATION; - - for (int s = 0; s < kNumStages; ++s) { - if (desc.fStages[s].fEnabled) { - GrStringBuilder matName; - tex_matrix_name(s, &matName); - GR_GL(BindAttribLocation(progID, - TEXMAT_ATTR_LOCATION(s), - matName.cstr())); - program->fUniLocations.fStages[s].fTextureMatrixUni = - BOGUS_MATRIX_UNI_LOCATION; - } - } -#endif - - GR_GL(BindAttribLocation(progID, COL_ATTR_LOCATION, COL_ATTR_NAME)); - - GR_GL(LinkProgram(progID)); - - GrGLint linked = GR_GL_INIT_ZERO; - GR_GL(GetProgramiv(progID, GR_GL_LINK_STATUS, &linked)); - if (!linked) { - GrGLint infoLen = GR_GL_INIT_ZERO; - GR_GL(GetProgramiv(progID, GR_GL_INFO_LOG_LENGTH, &infoLen)); - GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger - if (infoLen > 0) { - GR_GL(GetProgramInfoLog(progID, - infoLen+1, - NULL, - (char*)log.get())); - GrPrintf((char*)log.get()); - } - GrAssert(!"Error linking program"); - GR_GL(DeleteProgram(progID)); - program->fProgramID = 0; - return; - } - - // Get uniform locations -#if !ATTRIBUTE_MATRIX - program->fUniLocations.fViewMatrixUni = - GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME)); - GrAssert(-1 != program->fUniLocations.fViewMatrixUni); -#endif - for (int s = 0; s < kNumStages; ++s) { - StageUniLocations& locations = program->fUniLocations.fStages[s]; - if (desc.fStages[s].fEnabled) { -#if !ATTRIBUTE_MATRIX - if (locations.fTextureMatrixUni) { - GrTokenString texMName; - tex_matrix_name(s, &texMName); - locations.fTextureMatrixUni = GR_GL(GetUniformLocation( - progID, - texMName.cstr())); - GrAssert(-1 != locations.fTextureMatrixUni); - } else { - locations.fTextureMatrixUni = -1; - - } -#endif - - if (locations.fSamplerUni) { - GrTokenString samplerName; - sampler_name(s, &samplerName); - locations.fSamplerUni = GR_GL(GetUniformLocation( - progID, - samplerName.cstr())); - GrAssert(-1 != locations.fSamplerUni); - } else { - locations.fSamplerUni = -1; - } - - if (locations.fRadial2Uni) { - GrTokenString radial2ParamName; - radial2_param_name(s, &radial2ParamName); - locations.fRadial2Uni = GR_GL(GetUniformLocation( - progID, - radial2ParamName.cstr())); - GrAssert(-1 != locations.fRadial2Uni); - } else { - locations.fRadial2Uni = -1; - } - } else { - locations.fSamplerUni = -1; - locations.fRadial2Uni = -1; - locations.fTextureMatrixUni = -1; - } - } - GR_GL(UseProgram(progID)); - - // init sampler unis and set bogus values for state tracking - for (int s = 0; s < kNumStages; ++s) { - if (-1 != program->fUniLocations.fStages[s].fSamplerUni) { - GR_GL(Uniform1i(program->fUniLocations.fStages[s].fSamplerUni, s)); - } - program->fTextureMatrices[s] = GrMatrix::InvalidMatrix(); - program->fRadial2CenterX1[s] = GR_ScalarMax; - program->fRadial2Radius0[s] = -GR_ScalarMax; - } - program->fViewMatrix = GrMatrix::InvalidMatrix(); -} - -void GrGpuGLShaders2::getProgramDesc(GrPrimitiveType primType, ProgramDesc* desc) { - - // Must initialize all fields or cache will have false negatives! - desc->fVertexLayout = fGeometrySrc.fVertexLayout; - - desc->fOptFlags = 0; - if (kPoints_PrimitiveType != primType) { - desc->fOptFlags |= ProgramDesc::kNotPoints_OptFlagBit; - } -#if GR_AGGRESSIVE_SHADER_OPTS - if (!(desc->fVertexLayout & kColor_VertexLayoutBit) && - (0xffffffff == fCurrDrawState.fColor)) { - desc->fOptFlags |= ProgramDesc::kVertexColorAllOnes_OptFlagBit; - } -#endif - - for (int s = 0; s < kNumStages; ++s) { - StageDesc& stage = desc->fStages[s]; - - stage.fEnabled = VertexUsesStage(s, fGeometrySrc.fVertexLayout); - - if (stage.fEnabled) { - GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; - GrAssert(NULL != texture); - // we matrix to invert when orientation is TopDown, so make sure - // we aren't in that case before flagging as identity. - if (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) { - stage.fOptFlags = StageDesc::kIdentityMatrix_OptFlagBit; - } else if (!getSamplerMatrix(s).hasPerspective()) { - stage.fOptFlags = StageDesc::kNoPerspective_OptFlagBit; - } else { - stage.fOptFlags = 0; - } - switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) { - case GrSamplerState::kNormal_SampleMode: - stage.fCoordMapping = StageDesc::kIdentity_CoordMapping; - break; - case GrSamplerState::kRadial_SampleMode: - stage.fCoordMapping = StageDesc::kRadialGradient_CoordMapping; - break; - case GrSamplerState::kRadial2_SampleMode: - stage.fCoordMapping = StageDesc::kRadial2Gradient_CoordMapping; - break; - case GrSamplerState::kSweep_SampleMode: - stage.fCoordMapping = StageDesc::kSweepGradient_CoordMapping; - break; - default: - GrAssert(!"Unexpected sample mode!"); - break; - } - if (GrPixelConfigIsAlphaOnly(texture->config())) { - stage.fModulation = StageDesc::kAlpha_Modulation; - } else { - stage.fModulation = StageDesc::kColor_Modulation; - } - } else { - stage.fOptFlags = 0; - stage.fCoordMapping = (StageDesc::CoordMapping)0; - stage.fModulation = (StageDesc::Modulation)0; - } - } -} - -GrGLuint GrGpuGLShaders2::CompileShader(GrGLenum type, - int stringCnt, - const char** strings, - int* stringLengths) { - GrGLuint shader = GR_GL(CreateShader(type)); - if (0 == shader) { - return 0; - } - - GrGLint compiled = GR_GL_INIT_ZERO; - GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths)); - GR_GL(CompileShader(shader)); - GR_GL(GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled)); - - if (!compiled) { - GrGLint infoLen = GR_GL_INIT_ZERO; - GR_GL(GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen)); - GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger - if (infoLen > 0) { - GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get())); - for (int i = 0; i < stringCnt; ++i) { - if (NULL == stringLengths || stringLengths[i] < 0) { - GrPrintf(strings[i]); - } else { - GrPrintf("%.*s", stringLengths[i], strings[i]); - } - } - GrPrintf("\n%s", log.get()); - } - GrAssert(!"Shader compilation failed!"); - GR_GL(DeleteShader(shader)); - return 0; - } - return shader; -} - -void GrGpuGLShaders2::DeleteProgram(Program* program) { - GR_GL(DeleteShader(program->fVShaderID)); - GR_GL(DeleteShader(program->fFShaderID)); - GR_GL(DeleteProgram(program->fProgramID)); - GR_DEBUGCODE(memset(program, 0, sizeof(Program))); -} - - -GrGpuGLShaders2::GrGpuGLShaders2() { - - fProgram = NULL; - fProgramCache = new ProgramCache(); - -#if 0 - ProgramUnitTest(); -#endif -} - -GrGpuGLShaders2::~GrGpuGLShaders2() { - delete fProgramCache; -} - -const GrMatrix& GrGpuGLShaders2::getHWSamplerMatrix(int stage) { -#if ATTRIBUTE_MATRIX - return fHWDrawState.fSamplerStates[stage].getMatrix(); -#else - return fProgram->fTextureMatrices[stage]; -#endif -} - -void GrGpuGLShaders2::recordHWSamplerMatrix(int stage, const GrMatrix& matrix){ -#if ATTRIBUTE_MATRIX - fHWDrawState.fSamplerStates[stage].setMatrix(matrix); -#else - fProgram->fTextureMatrices[stage] = matrix; -#endif -} - -void GrGpuGLShaders2::resetContext() { - - INHERITED::resetContext(); - - fHWGeometryState.fVertexLayout = 0; - fHWGeometryState.fVertexOffset = ~0; - GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION)); - for (int t = 0; t < kMaxTexCoords; ++t) { - GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION(t))); - } - GR_GL(EnableVertexAttribArray(POS_ATTR_LOCATION)); - - fHWProgramID = 0; -} - -void GrGpuGLShaders2::flushViewMatrix() { - GrAssert(NULL != fCurrDrawState.fRenderTarget); - GrMatrix m ( - GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1, - 0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1, - 0, 0, GrMatrix::I()[8]); - m.setConcat(m, fCurrDrawState.fViewMatrix); - - // ES doesn't allow you to pass true to the transpose param, - // so do our own transpose - GrScalar mt[] = { - m[GrMatrix::kScaleX], - m[GrMatrix::kSkewY], - m[GrMatrix::kPersp0], - m[GrMatrix::kSkewX], - m[GrMatrix::kScaleY], - m[GrMatrix::kPersp1], - m[GrMatrix::kTransX], - m[GrMatrix::kTransY], - m[GrMatrix::kPersp2] - }; -#if ATTRIBUTE_MATRIX - GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+0, mt+0)); - GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+1, mt+3)); - GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+2, mt+6)); -#else - GR_GL(UniformMatrix3fv(fProgram->fUniLocations.fViewMatrixUni,1,false,mt)); -#endif -} - -void GrGpuGLShaders2::flushTextureMatrix(int stage) { - GrAssert(NULL != fCurrDrawState.fTextures[stage]); - - GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[stage]; - - GrMatrix m = getSamplerMatrix(stage); - GrSamplerState::SampleMode mode = - fCurrDrawState.fSamplerStates[0].getSampleMode(); - AdjustTextureMatrix(texture, mode, &m); - - // ES doesn't allow you to pass true to the transpose param, - // so do our own transpose - GrScalar mt[] = { - m[GrMatrix::kScaleX], - m[GrMatrix::kSkewY], - m[GrMatrix::kPersp0], - m[GrMatrix::kSkewX], - m[GrMatrix::kScaleY], - m[GrMatrix::kPersp1], - m[GrMatrix::kTransX], - m[GrMatrix::kTransY], - m[GrMatrix::kPersp2] - }; -#if ATTRIBUTE_MATRIX - GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+0, mt+0)); - GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+1, mt+3)); - GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+2, mt+6)); -#else - GR_GL(UniformMatrix3fv(fProgram->fUniLocations.fStages[stage].fTextureMatrixUni, - 1, false, mt)); -#endif -} - -void GrGpuGLShaders2::flushRadial2(int stage) { - - const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[stage]; - - GrScalar centerX1 = sampler.getRadial2CenterX1(); - GrScalar radius0 = sampler.getRadial2Radius0(); - - GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1; - - float unis[6] = { - GrScalarToFloat(a), - 1 / (2.f * unis[0]), - GrScalarToFloat(centerX1), - GrScalarToFloat(radius0), - GrScalarToFloat(GrMul(radius0, radius0)), - sampler.isRadial2PosRoot() ? 1.f : -1.f - }; - GR_GL(Uniform1fv(fProgram->fUniLocations.fStages[stage].fRadial2Uni, - 6, - unis)); -} - -void GrGpuGLShaders2::flushProgram(GrPrimitiveType type) { - ProgramDesc desc; - getProgramDesc(type, &desc); - fProgram = fProgramCache->getProgram(desc); - - if (fHWProgramID != fProgram->fProgramID) { - GR_GL(UseProgram(fProgram->fProgramID)); - fHWProgramID = fProgram->fProgramID; -#if GR_COLLECT_STATS - ++fStats.fProgChngCnt; -#endif - } -} - -bool GrGpuGLShaders2::flushGraphicsState(GrPrimitiveType type) { - - if (!flushGLStateCommon(type)) { - return false; - } - - if (fDirtyFlags.fRenderTargetChanged) { - // our coords are in pixel space and the GL matrices map to NDC - // so if the viewport changed, our matrix is now wrong. -#if ATTRIBUTE_MATRIX - fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix(); -#else - // we assume all shader matrices may be wrong after viewport changes - fProgramCache->invalidateViewMatrices(); -#endif - } - - flushProgram(type); - - if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) { - // invalidate the immediate mode color - fHWDrawState.fColor = GrColor_ILLEGAL; - } else { - if (fHWDrawState.fColor != fCurrDrawState.fColor && - (!GR_AGGRESSIVE_SHADER_OPTS || 0xffffffff != fCurrDrawState.fColor)) { - // avoid pushing the color attrib if the shader will optimize it out - - // OpenGL ES only supports the float varities of glVertexAttrib - float c[] = { - GrColorUnpackR(fCurrDrawState.fColor) / 255.f, - GrColorUnpackG(fCurrDrawState.fColor) / 255.f, - GrColorUnpackB(fCurrDrawState.fColor) / 255.f, - GrColorUnpackA(fCurrDrawState.fColor) / 255.f - }; - GR_GL(VertexAttrib4fv(COL_ATTR_LOCATION, c)); - fHWDrawState.fColor = fCurrDrawState.fColor; - } - } - -#if ATTRIBUTE_MATRIX - GrMatrix& currViewMatrix = fHWDrawState.fViewMatrix; -#else - GrMatrix& currViewMatrix = fProgram->fViewMatrix; -#endif - - if (currViewMatrix != fCurrDrawState.fViewMatrix) { - flushViewMatrix(); - currViewMatrix = fCurrDrawState.fViewMatrix; - } - - for (int s = 0; s < kNumStages; ++s) { - GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; - if (NULL != texture) { - if (-1 != fProgram->fUniLocations.fStages[s].fTextureMatrixUni && - (((1 << s) & fDirtyFlags.fTextureChangedMask) || - getHWSamplerMatrix(s) != getSamplerMatrix(s))) { - flushTextureMatrix(s); - recordHWSamplerMatrix(s, getSamplerMatrix(s)); - } - } - - const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s]; - if (-1 != fProgram->fUniLocations.fStages[s].fRadial2Uni && - (fProgram->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() || - fProgram->fRadial2Radius0[s] != sampler.getRadial2Radius0() || - fProgram->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) { - - flushRadial2(s); - - fProgram->fRadial2CenterX1[s] = sampler.getRadial2CenterX1(); - fProgram->fRadial2Radius0[s] = sampler.getRadial2Radius0(); - fProgram->fRadial2PosRoot[s] = sampler.isRadial2PosRoot(); - } - } - resetDirtyFlags(); - return true; -} - -void GrGpuGLShaders2::setupGeometry(int* startVertex, - int* startIndex, - int vertexCount, - int indexCount) { - - int newColorOffset; - int newTexCoordOffsets[kMaxTexCoords]; - - GrGLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout, - newTexCoordOffsets, - &newColorOffset); - int oldColorOffset; - int oldTexCoordOffsets[kMaxTexCoords]; - GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout, - oldTexCoordOffsets, - &oldColorOffset); - bool indexed = NULL != startIndex; - - int extraVertexOffset; - int extraIndexOffset; - setBuffers(indexed, &extraVertexOffset, &extraIndexOffset); - - GrGLenum scalarType; - bool texCoordNorm; - if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) { - scalarType = GrGLTextType; - texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED; - } else { - scalarType = GrGLType; - texCoordNorm = false; - } - - size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride; - *startVertex = 0; - if (indexed) { - *startIndex += extraIndexOffset; - } - - // all the Pointers must be set if any of these are true - bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty || - vertexOffset != fHWGeometryState.fVertexOffset || - newStride != oldStride; - - // position and tex coord offsets change if above conditions are true - // or the type/normalization changed based on text vs nontext type coords. - bool posAndTexChange = allOffsetsChange || - (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) && - (kTextFormat_VertexLayoutBit & - (fHWGeometryState.fVertexLayout ^ - fGeometrySrc.fVertexLayout))); - - if (posAndTexChange) { - GR_GL(VertexAttribPointer(POS_ATTR_LOCATION, 2, scalarType, - false, newStride, (GrGLvoid*)vertexOffset)); - fHWGeometryState.fVertexOffset = vertexOffset; - } - - for (int t = 0; t < kMaxTexCoords; ++t) { - if (newTexCoordOffsets[t] > 0) { - GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]); - if (oldTexCoordOffsets[t] <= 0) { - GR_GL(EnableVertexAttribArray(TEX_ATTR_LOCATION(t))); - GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType, - texCoordNorm, newStride, texCoordOffset)); - } else if (posAndTexChange || - newTexCoordOffsets[t] != oldTexCoordOffsets[t]) { - GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType, - texCoordNorm, newStride, texCoordOffset)); - } - } else if (oldTexCoordOffsets[t] > 0) { - GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION(t))); - } - } - - if (newColorOffset > 0) { - GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset); - if (oldColorOffset <= 0) { - GR_GL(EnableVertexAttribArray(COL_ATTR_LOCATION)); - GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4, - GR_GL_UNSIGNED_BYTE, - true, newStride, colorOffset)); - } else if (allOffsetsChange || newColorOffset != oldColorOffset) { - GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4, - GR_GL_UNSIGNED_BYTE, - true, newStride, colorOffset)); - } - } else if (oldColorOffset > 0) { - GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION)); - } - - fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout; - fHWGeometryState.fArrayPtrsDirty = false; -} diff --git a/gpu/src/GrGpuGLShaders2.h b/gpu/src/GrGpuGLShaders2.h deleted file mode 100644 index b9a019b..0000000 --- a/gpu/src/GrGpuGLShaders2.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - Copyright 2011 Google Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - - -#ifndef GrGpuGLShaders2_DEFINED -#define GrGpuGLShaders2_DEFINED - -#include "GrGpuGL.h" - -// Programmable OpenGL or OpenGL ES 2.0 -class GrGpuGLShaders2 : public GrGpuGL { -public: - GrGpuGLShaders2(); - virtual ~GrGpuGLShaders2(); - -protected: - // overrides from GrGpu - virtual bool flushGraphicsState(GrPrimitiveType type); - virtual void setupGeometry(int* startVertex, - int* startIndex, - int vertexCount, - int indexCount); - -private: - - virtual void resetContext(); - - // Helpers to make code more readable - const GrMatrix& getHWSamplerMatrix(int stage); - void recordHWSamplerMatrix(int stage, const GrMatrix& matrix); - - // sets the texture matrix uniform for currently bound program - void flushTextureMatrix(int stage); - - // sets the MVP matrix uniform for currently bound program - void flushViewMatrix(); - - // flushes the parameters to two point radial gradient - void flushRadial2(int stage); - - // called at flush time to setup the appropriate program - void flushProgram(GrPrimitiveType type); - - struct Program; - - struct StageDesc; - struct ProgramDesc; - - struct UniLocations; - struct StageUniLocations; - - struct ShaderCodeSegments; - - class ProgramCache; - - // gets a description of needed shader - void getProgramDesc(GrPrimitiveType primType, ProgramDesc* desc); - - // generates and compiles a program from a description and vertex layout - // will change GL's bound program - static void GenProgram(const ProgramDesc& desc, Program* program); - - // generates code for a stage of the shader - static void GenStageCode(int stageNum, - const StageDesc& desc, - const char* psInColor, - const char* psOutColor, - const char* vsInCoord, - ShaderCodeSegments* segments, - StageUniLocations* locations); - - // Compiles a GL shader, returns shader ID or 0 if failed - // params have same meaning as glShaderSource - static GrGLuint CompileShader(GrGLenum type, int stringCnt, - const char** strings, - int* stringLengths); - static void DeleteProgram(Program* program); - - void ProgramUnitTest(); - - ProgramCache* fProgramCache; - Program* fProgram; - GrGLuint fHWProgramID; - - typedef GrGpuGL INHERITED; -}; - -#endif - diff --git a/gpu/src/GrInOrderDrawBuffer.cpp b/gpu/src/GrInOrderDrawBuffer.cpp index be4db99..7df1f23 100644 --- a/gpu/src/GrInOrderDrawBuffer.cpp +++ b/gpu/src/GrInOrderDrawBuffer.cpp @@ -24,9 +24,10 @@ GrInOrderDrawBuffer::GrInOrderDrawBuffer(GrVertexBufferAllocPool* vertexPool, GrIndexBufferAllocPool* indexPool) : - fDraws(DRAWS_BLOCK_SIZE, fDrawsStorage), - fStates(STATES_BLOCK_SIZE, fStatesStorage), - fClips(CLIPS_BLOCK_SIZE, fClipsStorage), + fDraws(&fDrawStorage), + fStates(&fStateStorage), + fClears(&fClearStorage), + fClips(&fClipStorage), fClipSet(true), fLastRectVertexLayout(0), @@ -149,7 +150,12 @@ void GrInOrderDrawBuffer::drawRect(const GrRect& rect, GrAssert(0 == lastDraw.fIndexCount % 6); GrAssert(0 == lastDraw.fStartIndex); - appendToPreviousDraw = lastDraw.fVertexBuffer == fCurrPoolVertexBuffer && + bool clearSinceLastDraw = + fClears.count() && + fClears.back().fBeforeDrawIdx == fDraws.count(); + + appendToPreviousDraw = !clearSinceLastDraw && + lastDraw.fVertexBuffer == fCurrPoolVertexBuffer && (fCurrQuad * 4 + lastDraw.fStartVertex) == fCurrPoolStartVertex; if (appendToPreviousDraw) { lastDraw.fVertexCount += 4; @@ -287,6 +293,23 @@ void GrInOrderDrawBuffer::drawNonIndexed(GrPrimitiveType primitiveType, draw.fIndexBuffer = NULL; } +void GrInOrderDrawBuffer::clear(const GrIRect* rect, GrColor color) { + GrIRect r; + if (NULL == rect) { + // We could do something smart and remove previous draws and clears to + // the current render target. If we get that smart we have to make sure + // those draws aren't read before this clear (render-to-texture). + r.setLTRB(0, 0, + this->getRenderTarget()->width(), + this->getRenderTarget()->height()); + rect = &r; + } + Clear& clr = fClears.push_back(); + clr.fColor = color; + clr.fBeforeDrawIdx = fDraws.count(); + clr.fRect = *rect; +} + void GrInOrderDrawBuffer::reset() { GrAssert(!fReservedGeometry.fLocked); uint32_t numStates = fStates.count(); @@ -307,6 +330,8 @@ void GrInOrderDrawBuffer::reset() { fDraws.reset(); fStates.reset(); + fClears.reset(); + fVertexPool.reset(); fIndexPool.reset(); @@ -320,7 +345,7 @@ void GrInOrderDrawBuffer::playback(GrDrawTarget* target) { GrAssert(NULL != target); GrAssert(target != this); // not considered and why? - uint32_t numDraws = fDraws.count(); + int numDraws = fDraws.count(); if (!numDraws) { return; } @@ -334,10 +359,17 @@ void GrInOrderDrawBuffer::playback(GrDrawTarget* target) { // on the stack. GrDrawTarget::AutoGeometrySrcRestore agsr(target); - uint32_t currState = ~0; - uint32_t currClip = ~0; + int currState = ~0; + int currClip = ~0; + int currClear = 0; + + for (int i = 0; i < numDraws; ++i) { + while (currClear < fClears.count() && + i == fClears[currClear].fBeforeDrawIdx) { + target->clear(&fClears[currClear].fRect, fClears[currClear].fColor); + ++currClear; + } - for (uint32_t i = 0; i < numDraws; ++i) { const Draw& draw = fDraws[i]; if (draw.fStateChanged) { ++currState; @@ -366,6 +398,11 @@ void GrInOrderDrawBuffer::playback(GrDrawTarget* target) { draw.fVertexCount); } } + while (currClear < fClears.count()) { + GrAssert(fDraws.count() == fClears[currClear].fBeforeDrawIdx); + target->clear(&fClears[currClear].fRect, fClears[currClear].fColor); + ++currClear; + } } bool GrInOrderDrawBuffer::geometryHints(GrVertexLayout vertexLayout, diff --git a/gpu/src/GrMatrix.cpp b/gpu/src/GrMatrix.cpp index 0a2d1b2..476d9a2 100644 --- a/gpu/src/GrMatrix.cpp +++ b/gpu/src/GrMatrix.cpp @@ -19,6 +19,7 @@ #include "GrRect.h" #include <stddef.h> +#if 0 #if GR_SCALAR_IS_FLOAT const GrScalar GrMatrix::gRESCALE(GR_Scalar1); #else @@ -259,6 +260,26 @@ bool GrMatrix::isIdentity() const { } +bool GrMatrix::preservesAxisAlignment() const { + + // check if matrix is trans and scale only + static const int gAllowedMask1 = kScale_TypeBit | kTranslate_TypeBit; + + if (!(~gAllowedMask1 & fTypeMask)) { + return true; + } + + // check matrix is trans and skew only (0 scale) + static const int gAllowedMask2 = kScale_TypeBit | kSkew_TypeBit | + kTranslate_TypeBit | kZeroScale_TypeBit; + + if (!(~gAllowedMask2 & fTypeMask) && (kZeroScale_TypeBit & fTypeMask)) { + return true; + } + + return false; +} + GrScalar GrMatrix::getMaxStretch() const { if (fTypeMask & kPerspective_TypeBit) { @@ -611,7 +632,7 @@ void GrMatrix::UnitTest() { if (maxStretch > 0) { maxStretch = GrMul(GR_Scalar1 + GR_Scalar1 / 100, maxStretch); } - GrPoint origin = a.mapPoint(GrPoint(0,0)); + GrPoint origin = a.mapPoint(GrPoint::Make(0,0)); for (int j = 0; j < 9; ++j) { int mask, origMask = a.fTypeMask; @@ -648,8 +669,8 @@ void GrMatrix::UnitTest() { a.mapPerspective(&t2, &pt, 1); // full mult GrAssert(t0 == t1 && t1 == t2); if (maxStretch >= 0.f) { - GrVec vec; - vec.setBetween(t0, origin); + GrVec vec = origin - t0; +// vec.setBetween(t0, origin); GrScalar stretch = vec.length() / pt.distanceToOrigin(); GrAssert(stretch <= maxStretch); } @@ -668,6 +689,7 @@ void GrMatrix::UnitTest() { } /////////////////////////////////////////////////////////////////////////////// +#endif int Gr_clz(uint32_t n) { if (0 == n) { @@ -696,34 +718,3 @@ int Gr_clz(uint32_t n) { } return count; } - -/////////////////////////////////////////////////////////////////////////////// -#include "GrRect.h" - -void GrRect::setBounds(const GrPoint pts[], int count) { - if (count <= 0) { - this->setEmpty(); - } else { - GrScalar L, R, T, B; - L = R = pts[0].fX; - T = B = pts[0].fY; - for (int i = 1; i < count; i++) { - GrScalar x = pts[i].fX; - GrScalar y = pts[i].fY; - if (x < L) { - L = x; - } else if (x > R) { - R = x; - } - if (y < T) { - T = y; - } else if (y > B) { - B = y; - } - } - this->setLTRB(L, T, R, B); - } -} - - - diff --git a/gpu/src/GrPath.cpp b/gpu/src/GrPath.cpp index a740dfc..aa89d37 100644 --- a/gpu/src/GrPath.cpp +++ b/gpu/src/GrPath.cpp @@ -2,6 +2,7 @@ GrPath::GrPath() { fConvexHint = kNone_ConvexHint; + fConservativeBounds.setLargestInverted(); } GrPath::GrPath(const GrPath& src) : INHERITED() { @@ -40,6 +41,7 @@ void GrPath::ensureMoveTo() { if (fCmds.isEmpty() || this->wasLastVerb(kClose_PathCmd)) { *fCmds.append() = kMove_PathCmd; fPts.append()->set(0, 0); + fConservativeBounds.growToInclude(0,0); } } @@ -51,12 +53,14 @@ void GrPath::moveTo(GrScalar x, GrScalar y) { *fCmds.append() = kMove_PathCmd; fPts.append()->set(x, y); } + fConservativeBounds.growToInclude(x,y); } void GrPath::lineTo(GrScalar x, GrScalar y) { this->ensureMoveTo(); *fCmds.append() = kLine_PathCmd; fPts.append()->set(x, y); + fConservativeBounds.growToInclude(x,y); } void GrPath::quadTo(GrScalar x0, GrScalar y0, GrScalar x1, GrScalar y1) { @@ -64,6 +68,8 @@ void GrPath::quadTo(GrScalar x0, GrScalar y0, GrScalar x1, GrScalar y1) { *fCmds.append() = kQuadratic_PathCmd; fPts.append()->set(x0, y0); fPts.append()->set(x1, y1); + fConservativeBounds.growToInclude(x0,y0); + fConservativeBounds.growToInclude(x1,y1); } void GrPath::cubicTo(GrScalar x0, GrScalar y0, GrScalar x1, GrScalar y1, @@ -73,6 +79,9 @@ void GrPath::cubicTo(GrScalar x0, GrScalar y0, GrScalar x1, GrScalar y1, fPts.append()->set(x0, y0); fPts.append()->set(x1, y1); fPts.append()->set(x2, y2); + fConservativeBounds.growToInclude(x0,y0); + fConservativeBounds.growToInclude(x1,y1); + fConservativeBounds.growToInclude(x2,y2); } void GrPath::close() { @@ -95,6 +104,7 @@ void GrPath::offset(GrScalar tx, GrScalar ty) { iter->offset(tx, ty); ++iter; } + fConservativeBounds.offset(tx, ty); } /////////////////////////////////////////////////////////////////////////////// @@ -148,17 +158,18 @@ static void init_from_two_vecs(const GrVec& firstVec, void GrPath::resetFromIter(GrPathIter* iter) { fPts.reset(); fCmds.reset(); + fConservativeBounds.setLargestInverted(); fConvexHint = iter->convexHint(); // first point of the subpath - GrPoint firstPt(0,0); + GrPoint firstPt = { 0, 0 }; // first edge of the subpath - GrVec firstVec(0,0); + GrVec firstVec = { 0, 0 }; // vec of most recently processed edge, that wasn't degenerate - GrVec previousVec(0,0); + GrVec previousVec = { 0, 0 }; // most recently processed point - GrPoint previousPt(0,0); + GrPoint previousPt = { 0, 0 }; // sign indicates whether we're bending left or right GrScalar turnDir = 0; @@ -209,6 +220,9 @@ void GrPath::resetFromIter(GrPathIter* iter) { break; } int n = NumPathCmdPoints(cmd); + for (int i = 0; i < n; ++i) { + fConservativeBounds.growToInclude(pts[i].fX, pts[i].fY); + } if (0 == subPathPts && n > 0) { previousPt = pts[0]; firstPt = previousPt; @@ -225,8 +239,8 @@ void GrPath::resetFromIter(GrPathIter* iter) { if (numSubPaths < 2 && kNone_ConvexHint == fConvexHint) { while (consumed < n) { GrAssert(pts[consumed-1] == previousPt); - GrVec vec; - vec.setBetween(previousPt, pts[consumed]); + GrVec vec = pts[consumed] - previousPt; +// vec.setBetween(previousPt, pts[consumed]); if (vec.fX || vec.fY) { if (subPathPts >= 2) { if (0 == turnDir) { @@ -255,8 +269,8 @@ void GrPath::resetFromIter(GrPathIter* iter) { (!subPathClosed && kEnd_PathCmd == cmd ))) { // if an additional vector is needed to close the loop check // that it validates against the previous vector. - GrVec vec; - vec.setBetween(previousPt, firstPt); + GrVec vec = firstPt - previousPt; +// vec.setBetween(previousPt, firstPt); if (vec.fX || vec.fY) { if (!check_two_vecs(previousVec, vec, turnDir, &xDir, &yDir, &flipX, &flipY)) { @@ -409,6 +423,13 @@ GrPath::Iter::Iter(const GrPath& path) : fPath(&path) { this->rewind(); } +#ifdef SK_DEBUG +static bool containsInclusive(const GrRect& rect, const GrPoint& point) { + return point.fX >= rect.fLeft && point.fX <= rect.fRight && + point.fY >= rect.fTop && point.fY <= rect.fBottom; +} +#endif + GrPathCmd GrPath::Iter::next(GrPoint points[]) { if (fCmdIndex == fPath->fCmds.count()) { GrAssert(fPtIndex == fPath->fPts.count()); @@ -427,6 +448,7 @@ GrPathCmd GrPath::Iter::next(GrPoint points[]) { } fLastPt = srcPts[0]; GrAssert(fPtIndex <= fPath->fPts.count() + 1); + GrAssert(containsInclusive(fPath->getConservativeBounds(), srcPts[0])); fPtIndex += 1; break; case kLine_PathCmd: @@ -436,6 +458,7 @@ GrPathCmd GrPath::Iter::next(GrPoint points[]) { } fLastPt = srcPts[0]; GrAssert(fPtIndex <= fPath->fPts.count() + 1); + GrAssert(containsInclusive(fPath->getConservativeBounds(), srcPts[0])); fPtIndex += 1; break; case kQuadratic_PathCmd: @@ -446,6 +469,8 @@ GrPathCmd GrPath::Iter::next(GrPoint points[]) { } fLastPt = srcPts[1]; GrAssert(fPtIndex <= fPath->fPts.count() + 2); + GrAssert(containsInclusive(fPath->getConservativeBounds(), srcPts[0])); + GrAssert(containsInclusive(fPath->getConservativeBounds(), srcPts[1])); fPtIndex += 2; break; case kCubic_PathCmd: @@ -457,6 +482,9 @@ GrPathCmd GrPath::Iter::next(GrPoint points[]) { } fLastPt = srcPts[2]; GrAssert(fPtIndex <= fPath->fPts.count() + 3); + GrAssert(containsInclusive(fPath->getConservativeBounds(), srcPts[0])); + GrAssert(containsInclusive(fPath->getConservativeBounds(), srcPts[1])); + GrAssert(containsInclusive(fPath->getConservativeBounds(), srcPts[2])); fPtIndex += 3; break; case kClose_PathCmd: @@ -485,4 +513,11 @@ void GrPath::Iter::reset(const GrPath& path) { fCmdIndex = fPtIndex = 0; } +bool GrPath::Iter::getConservativeBounds(GrRect* rect) const { + if (!fPath->getConservativeBounds().isEmpty()) { + *rect = fPath->getConservativeBounds(); + return true; + } + return false; +} diff --git a/gpu/src/GrPathUtils.cpp b/gpu/src/GrPathUtils.cpp index 274dc49..115b0f6 100644 --- a/gpu/src/GrPathUtils.cpp +++ b/gpu/src/GrPathUtils.cpp @@ -52,10 +52,10 @@ uint32_t GrPathUtils::generateQuadraticPoints(const GrPoint& p0, } GrPoint q[] = { - GrPoint(GrScalarAve(p0.fX, p1.fX), GrScalarAve(p0.fY, p1.fY)), - GrPoint(GrScalarAve(p1.fX, p2.fX), GrScalarAve(p1.fY, p2.fY)), + { GrScalarAve(p0.fX, p1.fX), GrScalarAve(p0.fY, p1.fY) }, + { GrScalarAve(p1.fX, p2.fX), GrScalarAve(p1.fY, p2.fY) }, }; - GrPoint r(GrScalarAve(q[0].fX, q[1].fX), GrScalarAve(q[0].fY, q[1].fY)); + GrPoint r = { GrScalarAve(q[0].fX, q[1].fX), GrScalarAve(q[0].fY, q[1].fY) }; pointsLeft >>= 1; uint32_t a = generateQuadraticPoints(p0, q[0], r, tolSqd, points, pointsLeft); @@ -91,15 +91,15 @@ uint32_t GrPathUtils::generateCubicPoints(const GrPoint& p0, return 1; } GrPoint q[] = { - GrPoint(GrScalarAve(p0.fX, p1.fX), GrScalarAve(p0.fY, p1.fY)), - GrPoint(GrScalarAve(p1.fX, p2.fX), GrScalarAve(p1.fY, p2.fY)), - GrPoint(GrScalarAve(p2.fX, p3.fX), GrScalarAve(p2.fY, p3.fY)) + { GrScalarAve(p0.fX, p1.fX), GrScalarAve(p0.fY, p1.fY) }, + { GrScalarAve(p1.fX, p2.fX), GrScalarAve(p1.fY, p2.fY) }, + { GrScalarAve(p2.fX, p3.fX), GrScalarAve(p2.fY, p3.fY) } }; GrPoint r[] = { - GrPoint(GrScalarAve(q[0].fX, q[1].fX), GrScalarAve(q[0].fY, q[1].fY)), - GrPoint(GrScalarAve(q[1].fX, q[2].fX), GrScalarAve(q[1].fY, q[2].fY)) + { GrScalarAve(q[0].fX, q[1].fX), GrScalarAve(q[0].fY, q[1].fY) }, + { GrScalarAve(q[1].fX, q[2].fX), GrScalarAve(q[1].fY, q[2].fY) } }; - GrPoint s(GrScalarAve(r[0].fX, r[1].fX), GrScalarAve(r[0].fY, r[1].fY)); + GrPoint s = { GrScalarAve(r[0].fX, r[1].fX), GrScalarAve(r[0].fY, r[1].fY) }; pointsLeft >>= 1; uint32_t a = generateCubicPoints(p0, q[0], r[0], s, tolSqd, points, pointsLeft); uint32_t b = generateCubicPoints(s, r[1], q[2], p3, tolSqd, points, pointsLeft); diff --git a/gpu/src/GrPathUtils.h b/gpu/src/GrPathUtils.h index 97841dd..af05682 100644 --- a/gpu/src/GrPathUtils.h +++ b/gpu/src/GrPathUtils.h @@ -18,10 +18,9 @@ #define GrPathUtils_DEFINED #include "GrNoncopyable.h" -#include "GrScalar.h" +#include "GrPoint.h" class GrPathIter; -struct GrPoint; /** * Utilities for evaluating paths. diff --git a/gpu/src/GrStencil.cpp b/gpu/src/GrStencil.cpp index c366f61..a537e16 100644 --- a/gpu/src/GrStencil.cpp +++ b/gpu/src/GrStencil.cpp @@ -373,4 +373,4 @@ bool GrStencilSettings::GetClipPasses(GrSetOp op, GrCrash("Unknown set op"); } return false; -}
\ No newline at end of file +} diff --git a/gpu/src/GrTesselatedPathRenderer.cpp b/gpu/src/GrTesselatedPathRenderer.cpp index 8ed2c22..3993adb 100644 --- a/gpu/src/GrTesselatedPathRenderer.cpp +++ b/gpu/src/GrTesselatedPathRenderer.cpp @@ -55,8 +55,8 @@ static void combineData(GLdouble coords[3], void* vertexData[4], { PolygonData* polygonData = static_cast<PolygonData*>(data); int index = polygonData->fVertices->count(); - *polygonData->fVertices->append() = GrPoint(static_cast<float>(coords[0]), - static_cast<float>(coords[1])); + *polygonData->fVertices->append() = GrPoint::Make(static_cast<float>(coords[0]), + static_cast<float>(coords[1])); *outData = reinterpret_cast<void*>(index); } @@ -83,6 +83,59 @@ static unsigned fill_type_to_glu_winding_rule(GrPathFill fill) { GrTesselatedPathRenderer::GrTesselatedPathRenderer() { } +class Edge { + public: + Edge() {} + Edge(float x, float y, float z) : fX(x), fY(y), fZ(z) {} + GrPoint intersect(const Edge& other) { + return GrPoint::Make( + (fY * other.fZ - other.fY * fZ) / (fX * other.fY - other.fX * fY), + (fX * other.fZ - other.fX * fZ) / (other.fX * fY - fX * other.fY)); + } + float fX, fY, fZ; +}; + +typedef GrTDArray<Edge> EdgeArray; + +bool isCCW(const GrPoint* v) +{ + GrVec v1 = v[1] - v[0]; + GrVec v2 = v[2] - v[1]; + return v1.cross(v2) < 0; +} + +static size_t computeEdgesAndOffsetVertices(const GrMatrix& matrix, + const GrMatrix& inverse, + GrPoint* vertices, + size_t numVertices, + EdgeArray* edges) +{ + GrPoint p = vertices[numVertices - 1]; + matrix.mapPoints(&p, 1); + float sign = isCCW(vertices) ? -1.0f : 1.0f; + for (size_t i = 0; i < numVertices; ++i) { + GrPoint q = vertices[i]; + matrix.mapPoints(&q, 1); + if (p == q) continue; + GrVec tangent = GrVec::Make(p.fY - q.fY, q.fX - p.fX); + float scale = sign / tangent.length(); + float cross2 = p.fX * q.fY - q.fX * p.fY; + Edge edge(tangent.fX * scale, + tangent.fY * scale, + cross2 * scale + 0.5f); + *edges->append() = edge; + p = q; + } + Edge prev_edge = *edges->back(); + for (size_t i = 0; i < edges->count(); ++i) { + Edge edge = edges->at(i); + vertices[i] = prev_edge.intersect(edge); + inverse.mapPoints(&vertices[i], 1); + prev_edge = edge; + } + return edges->count(); +} + void GrTesselatedPathRenderer::drawPath(GrDrawTarget* target, GrDrawTarget::StageBitfield stages, GrPathIter* path, @@ -193,10 +246,10 @@ FINISHED: if (target->getViewInverse(&vmi)) { vmi.mapRect(&bounds); } - *vert++ = GrPoint(bounds.fLeft, bounds.fTop); - *vert++ = GrPoint(bounds.fLeft, bounds.fBottom); - *vert++ = GrPoint(bounds.fRight, bounds.fBottom); - *vert++ = GrPoint(bounds.fRight, bounds.fTop); + *vert++ = GrPoint::Make(bounds.fLeft, bounds.fTop); + *vert++ = GrPoint::Make(bounds.fLeft, bounds.fBottom); + *vert++ = GrPoint::Make(bounds.fRight, bounds.fBottom); + *vert++ = GrPoint::Make(bounds.fRight, bounds.fTop); subpathVertCount[subpath++] = 4; } @@ -205,9 +258,40 @@ FINISHED: size_t count = vert - base; + if (count < 3) { + delete[] base; + return; + } + if (subpathCnt == 1 && !inverted && path->convexHint() == kConvex_ConvexHint) { - target->setVertexSourceToArray(layout, base, count); - target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count); + if (target->isAntialiasState()) { + target->enableState(GrDrawTarget::kEdgeAA_StateBit); + EdgeArray edges; + GrMatrix inverse, matrix = target->getViewMatrix(); + target->getViewInverse(&inverse); + + count = computeEdgesAndOffsetVertices(matrix, inverse, base, count, &edges); + GrPoint triangle[3]; + triangle[0] = base[0]; + Edge triangleEdges[6]; + triangleEdges[0] = *edges.back(); + triangleEdges[1] = edges[0]; + for (size_t i = 1; i < count - 1; i++) { + triangle[1] = base[i]; + triangle[2] = base[i + 1]; + triangleEdges[2] = edges[i - 1]; + triangleEdges[3] = edges[i]; + triangleEdges[4] = edges[i]; + triangleEdges[5] = edges[i + 1]; + target->setVertexSourceToArray(layout, triangle, 3); + target->setEdgeAAData(&triangleEdges[0].fX); + target->drawNonIndexed(kTriangles_PrimitiveType, 0, 3); + } + target->disableState(GrDrawTarget::kEdgeAA_StateBit); + } else { + target->setVertexSourceToArray(layout, base, count); + target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count); + } delete[] base; return; } @@ -241,7 +325,7 @@ FINISHED: int end = start + subpathVertCount[sp]; for (; i < end; ++i) { double* inVertex = &inVertices[i * 3]; - *vertices.append() = GrPoint(inVertex[0], inVertex[1]); + *vertices.append() = GrPoint::Make(inVertex[0], inVertex[1]); internal_gluTessVertex(tess, inVertex, reinterpret_cast<void*>(i)); } internal_gluTessEndContour(tess); @@ -275,3 +359,14 @@ void GrTesselatedPathRenderer::drawPathToStencil(GrDrawTarget* target, const GrPoint* translate) { GrAlwaysAssert(!"multipass stencil should not be needed"); } + +bool GrTesselatedPathRenderer::supportsAA(GrDrawTarget* target, + GrPathIter* path, + GrPathFill fill) { + int subpathCnt = 0; + int tol = GrPathUtils::gTolerance; + GrPathUtils::worstCasePointCount(path, &subpathCnt, tol); + return (subpathCnt == 1 && + !IsFillInverted(fill) && + path->convexHint() == kConvex_ConvexHint); +} diff --git a/gpu/src/GrTextContext.cpp b/gpu/src/GrTextContext.cpp index 09113e0..0222042 100644 --- a/gpu/src/GrTextContext.cpp +++ b/gpu/src/GrTextContext.cpp @@ -36,10 +36,15 @@ void GrTextContext::flushGlyphs() { GrDrawTarget::AutoStateRestore asr(fDrawTarget); // setup our sampler state for our text texture/atlas - + GrSamplerState::Filter filter; + if (fExtMatrix.isIdentity()) { + filter = GrSamplerState::kNearest_Filter; + } else { + filter = GrSamplerState::kBilinear_Filter; + } GrSamplerState sampler(GrSamplerState::kRepeat_WrapMode, GrSamplerState::kRepeat_WrapMode, - !fExtMatrix.isIdentity()); + filter); fDrawTarget->setSamplerState(TEXT_STAGE, sampler); GrAssert(GrIsALIGN4(fCurrVertex)); diff --git a/gpu/src/GrTexture.cpp b/gpu/src/GrTexture.cpp index 1ea02a7..8df9c9e 100644 --- a/gpu/src/GrTexture.cpp +++ b/gpu/src/GrTexture.cpp @@ -16,6 +16,7 @@ #include "GrTexture.h" #include "GrContext.h" +#include "GrGpu.h" bool GrRenderTarget::readPixels(int left, int top, int width, int height, GrPixelConfig config, void* buffer) { @@ -28,6 +29,30 @@ bool GrRenderTarget::readPixels(int left, int top, int width, int height, config, buffer); } +void GrRenderTarget::flagAsNeedingResolve(const GrIRect* rect) { + if (kCanResolve_ResolveType == getResolveType()) { + if (NULL != rect) { + fResolveRect.join(*rect); + if (!fResolveRect.intersect(0, 0, this->width(), this->height())) { + fResolveRect.setEmpty(); + } + } else { + fResolveRect.setLTRB(0, 0, this->width(), this->height()); + } + } +} + +void GrRenderTarget::overrideResolveRect(const GrIRect rect) { + fResolveRect = rect; + if (fResolveRect.isEmpty()) { + fResolveRect.setLargestInverted(); + } else { + if (!fResolveRect.intersect(0, 0, this->width(), this->height())) { + fResolveRect.setLargestInverted(); + } + } +} + bool GrTexture::readPixels(int left, int top, int width, int height, GrPixelConfig config, void* buffer) { // go through context so that all necessary flushing occurs diff --git a/gpu/src/gr_files.mk b/gpu/src/gr_files.mk index a40d7bd..fef9784 100644 --- a/gpu/src/gr_files.mk +++ b/gpu/src/gr_files.mk @@ -11,7 +11,6 @@ SOURCE := \ GrGLTexture.cpp \ GrGLVertexBuffer.cpp \ GrGpu.cpp \ - GrGpuGLShaders2.cpp \ GrGpuGLFixed.cpp \ GrGpuFactory.cpp \ GrGLUtil.cpp \ diff --git a/gpu/src/gr_unittests.cpp b/gpu/src/gr_unittests.cpp index fd27f19..320dd15 100644 --- a/gpu/src/gr_unittests.cpp +++ b/gpu/src/gr_unittests.cpp @@ -152,7 +152,6 @@ void gr_run_unittests() { test_tdarray(); test_bsearch(); test_binHashKey(); - GrMatrix::UnitTest(); GrRedBlackTree<int>::UnitTest(); GrPath::ConvexUnitTest(); GrDrawTarget::VertexLayoutUnitTest(); diff --git a/gpu/src/mac/GrGLDefaultInterface_mac.cpp b/gpu/src/mac/GrGLDefaultInterface_mac.cpp index 802d717..b9396fa 100644 --- a/gpu/src/mac/GrGLDefaultInterface_mac.cpp +++ b/gpu/src/mac/GrGLDefaultInterface_mac.cpp @@ -91,14 +91,29 @@ void GrGLSetDefaultGLInterface() { gDefaultInterface.fTexEnvi = glTexEnvi; // mac uses GLenum for internalFormat param (non-standard) // amounts to int vs. uint. - gDefaultInterface.fTexImage2D = - (GrGLInterface::GrGLTexImage2DProc)glTexImage2D; + gDefaultInterface.fTexImage2D = (GrGLTexImage2DProc)glTexImage2D; gDefaultInterface.fTexParameteri = glTexParameteri; gDefaultInterface.fTexSubImage2D = glTexSubImage2D; - gDefaultInterface.fUniform1fv = glUniform1fv; + gDefaultInterface.fUniform1f = glUniform1f; gDefaultInterface.fUniform1i = glUniform1i; + gDefaultInterface.fUniform1fv = glUniform1fv; + gDefaultInterface.fUniform1iv = glUniform1iv; + gDefaultInterface.fUniform2f = glUniform2f; + gDefaultInterface.fUniform2i = glUniform2i; + gDefaultInterface.fUniform2fv = glUniform2fv; + gDefaultInterface.fUniform2iv = glUniform2iv; + gDefaultInterface.fUniform3f = glUniform3f; + gDefaultInterface.fUniform3i = glUniform3i; + gDefaultInterface.fUniform3fv = glUniform3fv; + gDefaultInterface.fUniform3iv = glUniform3iv; + gDefaultInterface.fUniform4f = glUniform4f; + gDefaultInterface.fUniform4i = glUniform4i; + gDefaultInterface.fUniform4fv = glUniform4fv; + gDefaultInterface.fUniform4iv = glUniform4iv; gDefaultInterface.fUniform4fv = glUniform4fv; + gDefaultInterface.fUniformMatrix2fv = glUniformMatrix2fv; gDefaultInterface.fUniformMatrix3fv = glUniformMatrix3fv; + gDefaultInterface.fUniformMatrix4fv = glUniformMatrix4fv; gDefaultInterface.fUnmapBuffer = glUnmapBuffer; gDefaultInterface.fUseProgram = glUseProgram; gDefaultInterface.fVertexAttrib4fv = glVertexAttrib4fv; diff --git a/gpu/src/unix/GrGLDefaultInterface_unix.cpp b/gpu/src/unix/GrGLDefaultInterface_unix.cpp new file mode 100644 index 0000000..ba67065 --- /dev/null +++ b/gpu/src/unix/GrGLDefaultInterface_unix.cpp @@ -0,0 +1,183 @@ +/* + Copyright 2011 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "GrGLInterface.h" + +#include <GL/glx.h> +#include <GL/gl.h> +#include <GL/glext.h> +#include <GL/glu.h> + +#define GR_GL_GET_PROC(F) gDefaultInterface.f ## F = (GrGL ## F ## Proc) \ + glXGetProcAddress(reinterpret_cast<const GLubyte*>("gl" #F)); +#define GR_GL_GET_PROC_SUFFIX(F, S) gDefaultInterface.f ## F = (GrGL ## F ## Proc) \ + glXGetProcAddress(reinterpret_cast<const GLubyte*>("gl" #F #S)); + +void GrGLSetDefaultGLInterface() { + static GrGLInterface gDefaultInterface; + static bool gDefaultInterfaceInit; + if (!gDefaultInterfaceInit && NULL != glXGetCurrentContext()) { + int major, minor; + const char* versionString = (const char*) glGetString(GL_VERSION); + const char* extString = (const char*) glGetString(GL_EXTENSIONS); + gl_version_from_string(&major, &minor, versionString); + + if (major == 1 && minor < 5) { + // We must have array and element_array buffer objects. + return; + } + + gDefaultInterface.fActiveTexture = glActiveTexture; + GR_GL_GET_PROC(AttachShader); + GR_GL_GET_PROC(BindAttribLocation); + GR_GL_GET_PROC(BindBuffer); + gDefaultInterface.fBindTexture = glBindTexture; + gDefaultInterface.fBlendColor = glBlendColor; + gDefaultInterface.fBlendFunc = glBlendFunc; + GR_GL_GET_PROC(BufferData); + GR_GL_GET_PROC(BufferSubData); + gDefaultInterface.fClear = glClear; + gDefaultInterface.fClearColor = glClearColor; + gDefaultInterface.fClearStencil = glClearStencil; + gDefaultInterface.fClientActiveTexture = glClientActiveTexture; + gDefaultInterface.fColorMask = glColorMask; + gDefaultInterface.fColorPointer = glColorPointer; + gDefaultInterface.fColor4ub = glColor4ub; + GR_GL_GET_PROC(CompileShader); + gDefaultInterface.fCompressedTexImage2D = glCompressedTexImage2D; + GR_GL_GET_PROC(CreateProgram); + GR_GL_GET_PROC(CreateShader); + gDefaultInterface.fCullFace = glCullFace; + GR_GL_GET_PROC(DeleteBuffers); + GR_GL_GET_PROC(DeleteProgram); + GR_GL_GET_PROC(DeleteShader); + gDefaultInterface.fDeleteTextures = glDeleteTextures; + gDefaultInterface.fDepthMask = glDepthMask; + gDefaultInterface.fDisable = glDisable; + gDefaultInterface.fDisableClientState = glDisableClientState; + GR_GL_GET_PROC(DisableVertexAttribArray); + gDefaultInterface.fDrawArrays = glDrawArrays; + gDefaultInterface.fDrawElements = glDrawElements; + gDefaultInterface.fEnable = glEnable; + gDefaultInterface.fEnableClientState = glEnableClientState; + GR_GL_GET_PROC(EnableVertexAttribArray); + gDefaultInterface.fFrontFace = glFrontFace; + GR_GL_GET_PROC(GenBuffers); + GR_GL_GET_PROC(GetBufferParameteriv); + gDefaultInterface.fGetError = glGetError; + gDefaultInterface.fGetIntegerv = glGetIntegerv; + GR_GL_GET_PROC(GetProgramInfoLog); + GR_GL_GET_PROC(GetProgramiv); + GR_GL_GET_PROC(GetShaderInfoLog); + GR_GL_GET_PROC(GetShaderiv); + gDefaultInterface.fGetString = glGetString; + gDefaultInterface.fGenTextures = glGenTextures; + GR_GL_GET_PROC(GetUniformLocation); + gDefaultInterface.fLineWidth = glLineWidth; + GR_GL_GET_PROC(LinkProgram); + gDefaultInterface.fLoadMatrixf = glLoadMatrixf; + GR_GL_GET_PROC(MapBuffer); + gDefaultInterface.fMatrixMode = glMatrixMode; + gDefaultInterface.fPointSize = glPointSize; + gDefaultInterface.fPixelStorei = glPixelStorei; + gDefaultInterface.fReadPixels = glReadPixels; + gDefaultInterface.fScissor = glScissor; + gDefaultInterface.fShadeModel = glShadeModel; + GR_GL_GET_PROC(ShaderSource); + gDefaultInterface.fStencilFunc = glStencilFunc; + GR_GL_GET_PROC(StencilFuncSeparate); + gDefaultInterface.fStencilMask = glStencilMask; + GR_GL_GET_PROC(StencilMaskSeparate); + gDefaultInterface.fStencilOp = glStencilOp; + GR_GL_GET_PROC(StencilOpSeparate); + gDefaultInterface.fTexCoordPointer = glTexCoordPointer; + gDefaultInterface.fTexEnvi = glTexEnvi; + gDefaultInterface.fTexImage2D = glTexImage2D; + gDefaultInterface.fTexParameteri = glTexParameteri; + gDefaultInterface.fTexSubImage2D = glTexSubImage2D; + GR_GL_GET_PROC(Uniform1f); + GR_GL_GET_PROC(Uniform1i); + GR_GL_GET_PROC(Uniform1fv); + GR_GL_GET_PROC(Uniform1iv); + GR_GL_GET_PROC(Uniform2f); + GR_GL_GET_PROC(Uniform2i); + GR_GL_GET_PROC(Uniform2fv); + GR_GL_GET_PROC(Uniform2iv); + GR_GL_GET_PROC(Uniform3f); + GR_GL_GET_PROC(Uniform3i); + GR_GL_GET_PROC(Uniform3fv); + GR_GL_GET_PROC(Uniform3iv); + GR_GL_GET_PROC(Uniform4f); + GR_GL_GET_PROC(Uniform4i); + GR_GL_GET_PROC(Uniform4fv); + GR_GL_GET_PROC(Uniform4iv); + GR_GL_GET_PROC(UniformMatrix2fv); + GR_GL_GET_PROC(UniformMatrix3fv); + GR_GL_GET_PROC(UniformMatrix4fv); + GR_GL_GET_PROC(UnmapBuffer); + GR_GL_GET_PROC(UseProgram); + GR_GL_GET_PROC(VertexAttrib4fv); + GR_GL_GET_PROC(VertexAttribPointer); + gDefaultInterface.fVertexPointer = glVertexPointer; + gDefaultInterface.fViewport = glViewport; + + // First look for GL3.0 FBO or GL_ARB_framebuffer_object (same since + // GL_ARB_framebuffer_object doesn't use ARB suffix.) + if (major >= 3 || has_gl_extension_from_string( + "GL_ARB_framebuffer_object", extString)) { + GR_GL_GET_PROC(GenFramebuffers); + GR_GL_GET_PROC(BindFramebuffer); + GR_GL_GET_PROC(FramebufferTexture2D); + GR_GL_GET_PROC(CheckFramebufferStatus); + GR_GL_GET_PROC(DeleteFramebuffers); + GR_GL_GET_PROC(RenderbufferStorage); + GR_GL_GET_PROC(GenRenderbuffers); + GR_GL_GET_PROC(DeleteRenderbuffers); + GR_GL_GET_PROC(FramebufferRenderbuffer); + GR_GL_GET_PROC(BindRenderbuffer); + GR_GL_GET_PROC(RenderbufferStorageMultisample); + GR_GL_GET_PROC(BlitFramebuffer); + } else if (has_gl_extension_from_string("GL_EXT_framebuffer_object", + extString)) { + GR_GL_GET_PROC_SUFFIX(GenFramebuffers, EXT); + GR_GL_GET_PROC_SUFFIX(BindFramebuffer, EXT); + GR_GL_GET_PROC_SUFFIX(FramebufferTexture2D, EXT); + GR_GL_GET_PROC_SUFFIX(CheckFramebufferStatus, EXT); + GR_GL_GET_PROC_SUFFIX(DeleteFramebuffers, EXT); + GR_GL_GET_PROC_SUFFIX(RenderbufferStorage, EXT); + GR_GL_GET_PROC_SUFFIX(GenRenderbuffers, EXT); + GR_GL_GET_PROC_SUFFIX(DeleteRenderbuffers, EXT); + GR_GL_GET_PROC_SUFFIX(FramebufferRenderbuffer, EXT); + GR_GL_GET_PROC_SUFFIX(BindRenderbuffer, EXT); + if (has_gl_extension_from_string("GL_EXT_framebuffer_multisample", + extString)) { + GR_GL_GET_PROC_SUFFIX(RenderbufferStorageMultisample, EXT); + } + if (has_gl_extension_from_string("GL_EXT_framebuffer_blit", + extString)) { + GR_GL_GET_PROC_SUFFIX(BlitFramebuffer, EXT); + } + } else { + // we must have FBOs + return; + } + gDefaultInterface.fBindingsExported = kDesktop_GrGLBinding; + + gDefaultInterfaceInit = true; + } + if (gDefaultInterfaceInit) + GrGLSetGLInterface(&gDefaultInterface); +} diff --git a/gpu/src/win/GrGLDefaultInterface_win.cpp b/gpu/src/win/GrGLDefaultInterface_win.cpp index 6227015..53fb26a 100644 --- a/gpu/src/win/GrGLDefaultInterface_win.cpp +++ b/gpu/src/win/GrGLDefaultInterface_win.cpp @@ -25,8 +25,8 @@ * Otherwise, a springboard would be needed that hides the calling convention. */ -#define GR_GL_GET_PROC(F) gDefaultInterface.f ## F = (GrGLInterface::GrGL ## F ## Proc) wglGetProcAddress("gl" #F); -#define GR_GL_GET_PROC_SUFFIX(F, S) gDefaultInterface.f ## F = (GrGLInterface::GrGL ## F ## Proc) wglGetProcAddress("gl" #F #S); +#define GR_GL_GET_PROC(F) gDefaultInterface.f ## F = (GrGL ## F ## Proc) wglGetProcAddress("gl" #F); +#define GR_GL_GET_PROC_SUFFIX(F, S) gDefaultInterface.f ## F = (GrGL ## F ## Proc) wglGetProcAddress("gl" #F #S); void GrGLSetDefaultGLInterface() { static GrGLInterface gDefaultInterface; @@ -117,10 +117,25 @@ void GrGLSetDefaultGLInterface() { GR_GL_GET_PROC(StencilFuncSeparate); GR_GL_GET_PROC(StencilMaskSeparate); GR_GL_GET_PROC(StencilOpSeparate); - GR_GL_GET_PROC(Uniform1fv); + GR_GL_GET_PROC(Uniform1f); GR_GL_GET_PROC(Uniform1i); + GR_GL_GET_PROC(Uniform1fv); + GR_GL_GET_PROC(Uniform1iv); + GR_GL_GET_PROC(Uniform2f); + GR_GL_GET_PROC(Uniform2i); + GR_GL_GET_PROC(Uniform2fv); + GR_GL_GET_PROC(Uniform2iv); + GR_GL_GET_PROC(Uniform3f); + GR_GL_GET_PROC(Uniform3i); + GR_GL_GET_PROC(Uniform3fv); + GR_GL_GET_PROC(Uniform3iv); + GR_GL_GET_PROC(Uniform4f); + GR_GL_GET_PROC(Uniform4i); GR_GL_GET_PROC(Uniform4fv); + GR_GL_GET_PROC(Uniform4iv); + GR_GL_GET_PROC(UniformMatrix2fv); GR_GL_GET_PROC(UniformMatrix3fv); + GR_GL_GET_PROC(UniformMatrix4fv); GR_GL_GET_PROC(UseProgram); GR_GL_GET_PROC(VertexAttrib4fv); GR_GL_GET_PROC(VertexAttribPointer); |