blob: fe6d0c37f7f088d7bc8239e889321f7b8a8a91e0 [file] [log] [blame]
/*
Copyright 2010 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 "GrGpu.h"
#include "GrMemory.h"
#include "GrTextStrike.h"
#include "GrTextureCache.h"
#include "GrClipIterator.h"
#include "GrIndexBuffer.h"
///////////////////////////////////////////////////////////////////////////////
size_t GrTexture::BytesPerPixel(PixelConfig config) {
switch (config) {
case kAlpha_8_PixelConfig:
case kIndex_8_PixelConfig:
return 1;
case kRGB_565_PixelConfig:
case kRGBA_4444_PixelConfig:
return 2;
case kRGBA_8888_PixelConfig:
case kRGBX_8888_PixelConfig:
return 4;
default:
return 0;
}
}
bool GrTexture::PixelConfigIsOpaque(PixelConfig config) {
switch (config) {
case GrTexture::kRGB_565_PixelConfig:
case GrTexture::kRGBX_8888_PixelConfig:
return true;
default:
return false;
}
}
///////////////////////////////////////////////////////////////////////////////
extern void gr_run_unittests();
GrGpu::GrGpu() : f8bitPaletteSupport(false),
fNPOTTextureSupport(kNone_NPOTTextureType),
fQuadIndexBuffer(NULL) {
#if GR_DEBUG
// gr_run_unittests();
#endif
resetStats();
}
GrGpu::~GrGpu() {
if (NULL != fQuadIndexBuffer) {
fQuadIndexBuffer->unref();
}
}
void GrGpu::resetContext() {
}
void GrGpu::unimpl(const char msg[]) {
// GrPrintf("--- GrGpu unimplemented(\"%s\")\n", msg);
}
///////////////////////////////////////////////////////////////////////////////
bool GrGpu::canDisableBlend() const {
if ((kOne_BlendCoeff == fCurrDrawState.fSrcBlend) &&
(kZero_BlendCoeff == fCurrDrawState.fDstBlend)) {
return true;
}
// If we have vertex color without alpha then we can't force blend off
if ((fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) ||
0xff != GrColorUnpackA(fCurrDrawState.fColor)) {
return false;
}
// If the src coef will always be 1...
if (kSA_BlendCoeff != fCurrDrawState.fSrcBlend &&
kOne_BlendCoeff != fCurrDrawState.fSrcBlend) {
return false;
}
// ...and the dst coef is always 0...
if (kISA_BlendCoeff != fCurrDrawState.fDstBlend &&
kZero_BlendCoeff != fCurrDrawState.fDstBlend) {
return false;
}
// ...and there isn't a texture with an alpha channel...
for (int s = 0; s < kNumStages; ++s) {
if (VertexUsesStage(s, fGeometrySrc.fVertexLayout)) {
GrAssert(NULL != fCurrDrawState.fTextures[s]);
GrTexture::PixelConfig config = fCurrDrawState.fTextures[s]->config();
if (GrTexture::kRGB_565_PixelConfig != config &&
GrTexture::kRGBX_8888_PixelConfig != config) {
return false;
}
}
}
// ...then we disable blend.
return true;
}
///////////////////////////////////////////////////////////////////////////////
static const int MAX_QUADS = 512; // max possible: (1 << 14) - 1;
GR_STATIC_ASSERT(4 * MAX_QUADS <= 65535);
static inline void fillIndices(uint16_t* indices, int quadCount) {
for (int i = 0; i < quadCount; ++i) {
indices[6 * i + 0] = 4 * i + 0;
indices[6 * i + 1] = 4 * i + 1;
indices[6 * i + 2] = 4 * i + 2;
indices[6 * i + 3] = 4 * i + 0;
indices[6 * i + 4] = 4 * i + 2;
indices[6 * i + 5] = 4 * i + 3;
}
}
const GrIndexBuffer* GrGpu::quadIndexBuffer() const {
if (NULL == fQuadIndexBuffer) {
static const int SIZE = sizeof(uint16_t) * 6 * MAX_QUADS;
GrGpu* me = const_cast<GrGpu*>(this);
fQuadIndexBuffer = me->createIndexBuffer(SIZE, false);
if (NULL != fQuadIndexBuffer) {
uint16_t* indices = (uint16_t*)fQuadIndexBuffer->lock();
if (NULL != indices) {
fillIndices(indices, MAX_QUADS);
fQuadIndexBuffer->unlock();
} else {
indices = (uint16_t*)GrMalloc(SIZE);
fillIndices(indices, MAX_QUADS);
if (!fQuadIndexBuffer->updateData(indices, SIZE)) {
fQuadIndexBuffer->unref();
fQuadIndexBuffer = NULL;
GrAssert(!"Can't get indices into buffer!");
}
GrFree(indices);
}
}
}
return fQuadIndexBuffer;
}
int GrGpu::maxQuadsInIndexBuffer() const {
return (NULL == this->quadIndexBuffer()) ? 0 : MAX_QUADS;
}
///////////////////////////////////////////////////////////////////////////////
void GrGpu::clipWillChange(const GrClip& clip) {
if (clip != fClip) {
fClipState.fClipIsDirty = true;
}
}
bool GrGpu::setupClipAndFlushState(PrimitiveType type) {
const GrIRect* r = NULL;
if (fCurrDrawState.fFlagBits & kClip_StateBit) {
fClipState.fClipInStencil = fClip.countRects() > 1;
if (fClipState.fClipInStencil &&
(fClipState.fClipIsDirty ||
fClipState.fStencilClipTarget != fCurrDrawState.fRenderTarget)) {
AutoStateRestore asr(this);
AutoGeometrySrcRestore agsr(this);
this->disableState(kClip_StateBit);
eraseStencilClip();
int rectTotal = fClip.countRects();
static const int PtsPerRect = 4;
// this may be called while geometry is already reserved by the
// client. So we use our own vertex array where we avoid malloc
// if we have 4 or fewer rects.
GrAutoSTMalloc<PtsPerRect * 4, GrPoint> vertices(PtsPerRect *
rectTotal);
this->setVertexSourceToArray(vertices.get(), 0);
int currRect = 0;
while (currRect < rectTotal) {
int rectCount = GrMin(this->maxQuadsInIndexBuffer(),
rectTotal - currRect);
GrPoint* verts = (GrPoint*)vertices +
(currRect * PtsPerRect);
for (int i = 0; i < rectCount; i++) {
GrRect r(fClip.getRects()[i + currRect]);
verts = r.setRectFan(verts);
}
this->setIndexSourceToBuffer(quadIndexBuffer());
this->setViewMatrix(GrMatrix::I());
this->setStencilPass((GrDrawTarget::StencilPass)kSetClip_StencilPass);
this->drawIndexed(GrGpu::kTriangles_PrimitiveType,
currRect * PtsPerRect, 0,
rectCount * PtsPerRect, rectCount * 6);
currRect += rectCount;
}
fClipState.fStencilClipTarget = fCurrDrawState.fRenderTarget;
}
fClipState.fClipIsDirty = false;
if (!fClipState.fClipInStencil) {
r = &fClip.getBounds();
}
}
// Must flush the scissor after graphics state
if (!flushGraphicsState(type)) {
return false;
}
flushScissor(r);
return true;
}
///////////////////////////////////////////////////////////////////////////////
void GrGpu::drawIndexed(PrimitiveType type,
uint32_t startVertex,
uint32_t startIndex,
uint32_t vertexCount,
uint32_t indexCount) {
GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
fReservedGeometry.fLocked);
GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fIndexSrc ||
fReservedGeometry.fLocked);
if (!setupClipAndFlushState(type)) {
return;
}
#if GR_COLLECT_STATS
fStats.fVertexCnt += vertexCount;
fStats.fIndexCnt += indexCount;
fStats.fDrawCnt += 1;
#endif
setupGeometry(startVertex, startIndex, vertexCount, indexCount);
drawIndexedHelper(type, startVertex, startIndex,
vertexCount, indexCount);
}
void GrGpu::drawNonIndexed(PrimitiveType type,
uint32_t startVertex,
uint32_t vertexCount) {
GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
fReservedGeometry.fLocked);
if (!setupClipAndFlushState(type)) {
return;
}
#if GR_COLLECT_STATS
fStats.fVertexCnt += vertexCount;
fStats.fDrawCnt += 1;
#endif
setupGeometry(startVertex, 0, vertexCount, 0);
drawNonIndexedHelper(type, startVertex, vertexCount);
}
bool GrGpu::acquireGeometryHelper(GrVertexLayout vertexLayout,
void** vertices,
void** indices) {
GrAssert((fReservedGeometry.fVertexCount == 0) ||
(NULL != vertices));
if (NULL != vertices) {
*vertices = fVertices.realloc(VertexSize(vertexLayout) *
fReservedGeometry.fVertexCount);
if (!*vertices && fReservedGeometry.fVertexCount) {
return false;
}
}
GrAssert((fReservedGeometry.fIndexCount == 0) ||
(NULL != indices));
if (NULL != indices) {
*indices = fIndices.realloc(sizeof(uint16_t) *
fReservedGeometry.fIndexCount);
if (!*indices && fReservedGeometry.fIndexCount) {
return false;
}
}
return true;
}
void GrGpu::releaseGeometryHelper() {
return;
}
///////////////////////////////////////////////////////////////////////////////
const GrGpu::Stats& GrGpu::getStats() const {
return fStats;
}
void GrGpu::resetStats() {
memset(&fStats, 0, sizeof(fStats));
}
void GrGpu::printStats() const {
if (GR_COLLECT_STATS) {
GrPrintf(
"-v-------------------------GPU STATS----------------------------v-\n"
"Stats collection is: %s\n"
"Draws: %04d, Verts: %04d, Indices: %04d\n"
"ProgChanges: %04d, TexChanges: %04d, RTChanges: %04d\n"
"TexCreates: %04d, RTCreates:%04d\n"
"-^--------------------------------------------------------------^-\n",
(GR_COLLECT_STATS ? "ON" : "OFF"),
fStats.fDrawCnt, fStats.fVertexCnt, fStats.fIndexCnt,
fStats.fProgChngCnt, fStats.fTextureChngCnt, fStats.fRenderTargetChngCnt,
fStats.fTextureCreateCnt, fStats.fRenderTargetCreateCnt);
}
}
////////////////////////////////////////////////////////////////////////////////
GrTexture::~GrTexture() {
// use this to set a break-point if needed
// Gr_clz(3);
}
const GrSamplerState GrSamplerState::gClampNoFilter(
GrSamplerState::kClamp_WrapMode,
GrSamplerState::kClamp_WrapMode,
GrSamplerState::kNormal_SampleMode,
false);