| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 | 8 |
| 9 #include "GrGLGpu.h" | 9 #include "GrGLGpu.h" |
| 10 #include "GrGLStencilAttachment.h" | 10 #include "GrGLStencilAttachment.h" |
| 11 #include "GrGLTextureRenderTarget.h" | 11 #include "GrGLTextureRenderTarget.h" |
| 12 #include "GrGpuResourcePriv.h" | 12 #include "GrGpuResourcePriv.h" |
| 13 #include "GrPipeline.h" | 13 #include "GrPipeline.h" |
| 14 #include "GrRenderTargetPriv.h" | 14 #include "GrRenderTargetPriv.h" |
| 15 #include "GrSurfacePriv.h" | 15 #include "GrSurfacePriv.h" |
| 16 #include "GrTemplates.h" | 16 #include "GrTemplates.h" |
| 17 #include "GrTexturePriv.h" | 17 #include "GrTexturePriv.h" |
| 18 #include "GrTypes.h" | 18 #include "GrTypes.h" |
| 19 #include "GrVertices.h" | 19 #include "GrVertices.h" |
| 20 #include "builders/GrGLShaderStringBuilder.h" | |
| 21 #include "SkStrokeRec.h" | 20 #include "SkStrokeRec.h" |
| 22 #include "SkTemplates.h" | 21 #include "SkTemplates.h" |
| 23 | 22 |
| 24 #define GL_CALL(X) GR_GL_CALL(this->glInterface(), X) | 23 #define GL_CALL(X) GR_GL_CALL(this->glInterface(), X) |
| 25 #define GL_CALL_RET(RET, X) GR_GL_CALL_RET(this->glInterface(), RET, X) | 24 #define GL_CALL_RET(RET, X) GR_GL_CALL_RET(this->glInterface(), RET, X) |
| 26 | 25 |
| 27 #define SKIP_CACHE_CHECK true | 26 #define SKIP_CACHE_CHECK true |
| 28 | 27 |
| 29 #if GR_GL_CHECK_ALLOC_WITH_GET_ERROR | 28 #if GR_GL_CHECK_ALLOC_WITH_GET_ERROR |
| 30 #define CLEAR_ERROR_BEFORE_ALLOC(iface) GrGLClearErr(iface) | 29 #define CLEAR_ERROR_BEFORE_ALLOC(iface) GrGLClearErr(iface) |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 194 | 193 |
| 195 fLastSuccessfulStencilFmtIdx = 0; | 194 fLastSuccessfulStencilFmtIdx = 0; |
| 196 fHWProgramID = 0; | 195 fHWProgramID = 0; |
| 197 fTempSrcFBOID = 0; | 196 fTempSrcFBOID = 0; |
| 198 fTempDstFBOID = 0; | 197 fTempDstFBOID = 0; |
| 199 fStencilClearFBOID = 0; | 198 fStencilClearFBOID = 0; |
| 200 | 199 |
| 201 if (this->glCaps().shaderCaps()->pathRenderingSupport()) { | 200 if (this->glCaps().shaderCaps()->pathRenderingSupport()) { |
| 202 fPathRendering.reset(new GrGLPathRendering(this)); | 201 fPathRendering.reset(new GrGLPathRendering(this)); |
| 203 } | 202 } |
| 204 | |
| 205 this->createCopyProgram(); | |
| 206 } | 203 } |
| 207 | 204 |
| 208 GrGLGpu::~GrGLGpu() { | 205 GrGLGpu::~GrGLGpu() { |
| 209 if (0 != fHWProgramID) { | 206 if (0 != fHWProgramID) { |
| 210 // detach the current program so there is no confusion on OpenGL's part | 207 // detach the current program so there is no confusion on OpenGL's part |
| 211 // that we want it to be deleted | 208 // that we want it to be deleted |
| 209 SkASSERT(fHWProgramID == fCurrentProgram->programID()); |
| 212 GL_CALL(UseProgram(0)); | 210 GL_CALL(UseProgram(0)); |
| 213 } | 211 } |
| 214 | 212 |
| 215 if (0 != fTempSrcFBOID) { | 213 if (0 != fTempSrcFBOID) { |
| 216 GL_CALL(DeleteFramebuffers(1, &fTempSrcFBOID)); | 214 GL_CALL(DeleteFramebuffers(1, &fTempSrcFBOID)); |
| 217 } | 215 } |
| 218 if (0 != fTempDstFBOID) { | 216 if (0 != fTempDstFBOID) { |
| 219 GL_CALL(DeleteFramebuffers(1, &fTempDstFBOID)); | 217 GL_CALL(DeleteFramebuffers(1, &fTempDstFBOID)); |
| 220 } | 218 } |
| 221 if (0 != fStencilClearFBOID) { | 219 if (0 != fStencilClearFBOID) { |
| 222 GL_CALL(DeleteFramebuffers(1, &fStencilClearFBOID)); | 220 GL_CALL(DeleteFramebuffers(1, &fStencilClearFBOID)); |
| 223 } | 221 } |
| 224 | 222 |
| 225 if (0 != fCopyProgram.fArrayBuffer) { | |
| 226 GL_CALL(DeleteBuffers(1, &fCopyProgram.fArrayBuffer)); | |
| 227 } | |
| 228 | |
| 229 if (0 != fCopyProgram.fProgram) { | |
| 230 GL_CALL(DeleteProgram(fCopyProgram.fProgram)); | |
| 231 } | |
| 232 | |
| 233 delete fProgramCache; | 223 delete fProgramCache; |
| 234 } | 224 } |
| 235 | 225 |
| 236 void GrGLGpu::contextAbandoned() { | 226 void GrGLGpu::contextAbandoned() { |
| 237 INHERITED::contextAbandoned(); | 227 INHERITED::contextAbandoned(); |
| 238 fProgramCache->abandon(); | 228 fProgramCache->abandon(); |
| 239 fHWProgramID = 0; | 229 fHWProgramID = 0; |
| 240 fTempSrcFBOID = 0; | 230 fTempSrcFBOID = 0; |
| 241 fTempDstFBOID = 0; | 231 fTempDstFBOID = 0; |
| 242 fStencilClearFBOID = 0; | 232 fStencilClearFBOID = 0; |
| 243 fCopyProgram.fArrayBuffer = 0; | |
| 244 fCopyProgram.fProgram = 0; | |
| 245 if (this->glCaps().shaderCaps()->pathRenderingSupport()) { | 233 if (this->glCaps().shaderCaps()->pathRenderingSupport()) { |
| 246 this->glPathRendering()->abandonGpuResources(); | 234 this->glPathRendering()->abandonGpuResources(); |
| 247 } | 235 } |
| 248 } | 236 } |
| 249 | 237 |
| 250 /////////////////////////////////////////////////////////////////////////////// | 238 /////////////////////////////////////////////////////////////////////////////// |
| 251 GrPixelConfig GrGLGpu::preferredReadPixelsConfig(GrPixelConfig readConfig, | 239 GrPixelConfig GrGLGpu::preferredReadPixelsConfig(GrPixelConfig readConfig, |
| 252 GrPixelConfig surfaceConfig) co
nst { | 240 GrPixelConfig surfaceConfig) co
nst { |
| 253 if (GR_GL_RGBA_8888_PIXEL_OPS_SLOW && kRGBA_8888_GrPixelConfig == readConfig
) { | 241 if (GR_GL_RGBA_8888_PIXEL_OPS_SLOW && kRGBA_8888_GrPixelConfig == readConfig
) { |
| 254 return kBGRA_8888_GrPixelConfig; | 242 return kBGRA_8888_GrPixelConfig; |
| (...skipping 1167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1422 | 1410 |
| 1423 bool GrGLGpu::flushGLState(const DrawArgs& args) { | 1411 bool GrGLGpu::flushGLState(const DrawArgs& args) { |
| 1424 GrXferProcessor::BlendInfo blendInfo; | 1412 GrXferProcessor::BlendInfo blendInfo; |
| 1425 const GrPipeline& pipeline = *args.fPipeline; | 1413 const GrPipeline& pipeline = *args.fPipeline; |
| 1426 args.fPipeline->getXferProcessor()->getBlendInfo(&blendInfo); | 1414 args.fPipeline->getXferProcessor()->getBlendInfo(&blendInfo); |
| 1427 | 1415 |
| 1428 this->flushDither(pipeline.isDitherState()); | 1416 this->flushDither(pipeline.isDitherState()); |
| 1429 this->flushColorWrite(blendInfo.fWriteColor); | 1417 this->flushColorWrite(blendInfo.fWriteColor); |
| 1430 this->flushDrawFace(pipeline.getDrawFace()); | 1418 this->flushDrawFace(pipeline.getDrawFace()); |
| 1431 | 1419 |
| 1432 SkAutoTUnref<GrGLProgram> program(fProgramCache->refProgram(args)); | 1420 fCurrentProgram.reset(fProgramCache->getProgram(args)); |
| 1433 if (!program) { | 1421 if (NULL == fCurrentProgram.get()) { |
| 1434 GrContextDebugf(this->getContext(), "Failed to create program!\n"); | 1422 GrContextDebugf(this->getContext(), "Failed to create program!\n"); |
| 1435 return false; | 1423 return false; |
| 1436 } | 1424 } |
| 1437 | 1425 |
| 1438 GrGLuint programID = program->programID(); | 1426 fCurrentProgram.get()->ref(); |
| 1427 |
| 1428 GrGLuint programID = fCurrentProgram->programID(); |
| 1439 if (fHWProgramID != programID) { | 1429 if (fHWProgramID != programID) { |
| 1440 GL_CALL(UseProgram(programID)); | 1430 GL_CALL(UseProgram(programID)); |
| 1441 fHWProgramID = programID; | 1431 fHWProgramID = programID; |
| 1442 } | 1432 } |
| 1443 | 1433 |
| 1444 if (blendInfo.fWriteColor) { | 1434 if (blendInfo.fWriteColor) { |
| 1445 this->flushBlend(blendInfo); | 1435 this->flushBlend(blendInfo); |
| 1446 } | 1436 } |
| 1447 | 1437 |
| 1448 program->setData(*args.fPrimitiveProcessor, pipeline, *args.fBatchTracker); | 1438 fCurrentProgram->setData(*args.fPrimitiveProcessor, pipeline, *args.fBatchTr
acker); |
| 1449 | 1439 |
| 1450 GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(pipeline.getRenderTa
rget()); | 1440 GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(pipeline.getRenderTa
rget()); |
| 1451 this->flushStencil(pipeline.getStencil()); | 1441 this->flushStencil(pipeline.getStencil()); |
| 1452 this->flushScissor(pipeline.getScissorState(), glRT->getViewport(), glRT->or
igin()); | 1442 this->flushScissor(pipeline.getScissorState(), glRT->getViewport(), glRT->or
igin()); |
| 1453 this->flushHWAAState(glRT, pipeline.isHWAntialiasState()); | 1443 this->flushHWAAState(glRT, pipeline.isHWAntialiasState()); |
| 1454 | 1444 |
| 1455 // This must come after textures are flushed because a texture may need | 1445 // This must come after textures are flushed because a texture may need |
| 1456 // to be msaa-resolved (which will modify bound FBO state). | 1446 // to be msaa-resolved (which will modify bound FBO state). |
| 1457 this->flushRenderTarget(glRT, NULL); | 1447 this->flushRenderTarget(glRT, NULL); |
| 1458 | 1448 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1493 | 1483 |
| 1494 uint32_t usedAttribArraysMask = 0; | 1484 uint32_t usedAttribArraysMask = 0; |
| 1495 size_t offset = 0; | 1485 size_t offset = 0; |
| 1496 | 1486 |
| 1497 for (int attribIndex = 0; attribIndex < vaCount; attribIndex++) { | 1487 for (int attribIndex = 0; attribIndex < vaCount; attribIndex++) { |
| 1498 const GrGeometryProcessor::Attribute& attrib = primProc.getAttrib(at
tribIndex); | 1488 const GrGeometryProcessor::Attribute& attrib = primProc.getAttrib(at
tribIndex); |
| 1499 usedAttribArraysMask |= (1 << attribIndex); | 1489 usedAttribArraysMask |= (1 << attribIndex); |
| 1500 GrVertexAttribType attribType = attrib.fType; | 1490 GrVertexAttribType attribType = attrib.fType; |
| 1501 attribState->set(this, | 1491 attribState->set(this, |
| 1502 attribIndex, | 1492 attribIndex, |
| 1503 vbuf->bufferID(), | 1493 vbuf, |
| 1504 GrGLAttribTypeToLayout(attribType).fCount, | 1494 GrGLAttribTypeToLayout(attribType).fCount, |
| 1505 GrGLAttribTypeToLayout(attribType).fType, | 1495 GrGLAttribTypeToLayout(attribType).fType, |
| 1506 GrGLAttribTypeToLayout(attribType).fNormalized, | 1496 GrGLAttribTypeToLayout(attribType).fNormalized, |
| 1507 stride, | 1497 stride, |
| 1508 reinterpret_cast<GrGLvoid*>(vertexOffsetInBytes + o
ffset)); | 1498 reinterpret_cast<GrGLvoid*>(vertexOffsetInBytes + o
ffset)); |
| 1509 offset += attrib.fOffset; | 1499 offset += attrib.fOffset; |
| 1510 } | 1500 } |
| 1511 attribState->disableUnusedArrays(this, usedAttribArraysMask); | 1501 attribState->disableUnusedArrays(this, usedAttribArraysMask); |
| 1512 } | 1502 } |
| 1513 } | 1503 } |
| (...skipping 1107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2621 | 2611 |
| 2622 void GrGLGpu::unbindTextureFromFBO(GrGLenum fboTarget) { | 2612 void GrGLGpu::unbindTextureFromFBO(GrGLenum fboTarget) { |
| 2623 GR_GL_CALL(this->glInterface(), FramebufferTexture2D(fboTarget, | 2613 GR_GL_CALL(this->glInterface(), FramebufferTexture2D(fboTarget, |
| 2624 GR_GL_COLOR_ATTACHMENT0
, | 2614 GR_GL_COLOR_ATTACHMENT0
, |
| 2625 GR_GL_TEXTURE_2D, | 2615 GR_GL_TEXTURE_2D, |
| 2626 0, | 2616 0, |
| 2627 0)); | 2617 0)); |
| 2628 } | 2618 } |
| 2629 | 2619 |
| 2630 bool GrGLGpu::initCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc)
{ | 2620 bool GrGLGpu::initCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc)
{ |
| 2631 // If the src is a texture, we can implement the blit as a draw assuming the
config is | 2621 // In here we look for opportunities to use CopyTexSubImage, or fbo blit. If
neither are |
| 2632 // renderable. | |
| 2633 if (src->asTexture() && this->caps()->isConfigRenderable(src->config(), fals
e)) { | |
| 2634 desc->fOrigin = kDefault_GrSurfaceOrigin; | |
| 2635 desc->fFlags = kRenderTarget_GrSurfaceFlag; | |
| 2636 desc->fConfig = src->config(); | |
| 2637 return true; | |
| 2638 } | |
| 2639 | |
| 2640 // We look for opportunities to use CopyTexSubImage, or fbo blit. If neither
are | |
| 2641 // possible and we return false to fallback to creating a render target dst
for render-to- | 2622 // possible and we return false to fallback to creating a render target dst
for render-to- |
| 2642 // texture. This code prefers CopyTexSubImage to fbo blit and avoids trigger
ing temporary fbo | 2623 // texture. This code prefers CopyTexSubImage to fbo blit and avoids trigger
ing temporary fbo |
| 2643 // creation. It isn't clear that avoiding temporary fbo creation is actually
optimal. | 2624 // creation. It isn't clear that avoiding temporary fbo creation is actually
optimal. |
| 2644 | 2625 |
| 2645 // Check for format issues with glCopyTexSubImage2D | 2626 // Check for format issues with glCopyTexSubImage2D |
| 2646 if (kGLES_GrGLStandard == this->glStandard() && this->glCaps().bgraIsInterna
lFormat() && | 2627 if (kGLES_GrGLStandard == this->glStandard() && this->glCaps().bgraIsInterna
lFormat() && |
| 2647 kBGRA_8888_GrPixelConfig == src->config()) { | 2628 kBGRA_8888_GrPixelConfig == src->config()) { |
| 2648 // glCopyTexSubImage2D doesn't work with this config. If the bgra can be
used with fbo blit | 2629 // glCopyTexSubImage2D doesn't work with this config. If the bgra can be
used with fbo blit |
| 2649 // then we set up for that, otherwise fail. | 2630 // then we set up for that, otherwise fail. |
| 2650 if (this->caps()->isConfigRenderable(kBGRA_8888_GrPixelConfig, false)) { | 2631 if (this->caps()->isConfigRenderable(kBGRA_8888_GrPixelConfig, false)) { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 2676 desc->fConfig = src->config(); | 2657 desc->fConfig = src->config(); |
| 2677 desc->fOrigin = src->origin(); | 2658 desc->fOrigin = src->origin(); |
| 2678 desc->fFlags = kNone_GrSurfaceFlags; | 2659 desc->fFlags = kNone_GrSurfaceFlags; |
| 2679 return true; | 2660 return true; |
| 2680 } | 2661 } |
| 2681 | 2662 |
| 2682 bool GrGLGpu::copySurface(GrSurface* dst, | 2663 bool GrGLGpu::copySurface(GrSurface* dst, |
| 2683 GrSurface* src, | 2664 GrSurface* src, |
| 2684 const SkIRect& srcRect, | 2665 const SkIRect& srcRect, |
| 2685 const SkIPoint& dstPoint) { | 2666 const SkIPoint& dstPoint) { |
| 2686 if (src->asTexture() && dst->asRenderTarget()) { | 2667 bool copied = false; |
| 2687 this->copySurfaceAsDraw(dst, src, srcRect, dstPoint); | 2668 if (can_copy_texsubimage(dst, src, this)) { |
| 2669 GrGLuint srcFBO; |
| 2670 GrGLIRect srcVP; |
| 2671 srcFBO = this->bindSurfaceAsFBO(src, GR_GL_FRAMEBUFFER, &srcVP, kSrc_Tem
pFBOTarget); |
| 2672 GrGLTexture* dstTex = static_cast<GrGLTexture*>(dst->asTexture()); |
| 2673 SkASSERT(dstTex); |
| 2674 // We modified the bound FBO |
| 2675 fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; |
| 2676 GrGLIRect srcGLRect; |
| 2677 srcGLRect.setRelativeTo(srcVP, |
| 2678 srcRect.fLeft, |
| 2679 srcRect.fTop, |
| 2680 srcRect.width(), |
| 2681 srcRect.height(), |
| 2682 src->origin()); |
| 2683 |
| 2684 this->setScratchTextureUnit(); |
| 2685 GL_CALL(BindTexture(GR_GL_TEXTURE_2D, dstTex->textureID())); |
| 2686 GrGLint dstY; |
| 2687 if (kBottomLeft_GrSurfaceOrigin == dst->origin()) { |
| 2688 dstY = dst->height() - (dstPoint.fY + srcGLRect.fHeight); |
| 2689 } else { |
| 2690 dstY = dstPoint.fY; |
| 2691 } |
| 2692 GL_CALL(CopyTexSubImage2D(GR_GL_TEXTURE_2D, 0, |
| 2693 dstPoint.fX, dstY, |
| 2694 srcGLRect.fLeft, srcGLRect.fBottom, |
| 2695 srcGLRect.fWidth, srcGLRect.fHeight)); |
| 2696 copied = true; |
| 2697 if (srcFBO) { |
| 2698 this->unbindTextureFromFBO(GR_GL_FRAMEBUFFER); |
| 2699 } |
| 2700 } else if (can_blit_framebuffer(dst, src, this)) { |
| 2701 SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, |
| 2702 srcRect.width(), srcRect.height()); |
| 2703 bool selfOverlap = false; |
| 2704 if (dst == src) { |
| 2705 selfOverlap = SkIRect::IntersectsNoEmptyCheck(dstRect, srcRect); |
| 2706 } |
| 2707 |
| 2708 if (!selfOverlap) { |
| 2709 GrGLuint dstFBO; |
| 2710 GrGLuint srcFBO; |
| 2711 GrGLIRect dstVP; |
| 2712 GrGLIRect srcVP; |
| 2713 dstFBO = this->bindSurfaceAsFBO(dst, GR_GL_DRAW_FRAMEBUFFER, &dstVP, |
| 2714 kDst_TempFBOTarget); |
| 2715 srcFBO = this->bindSurfaceAsFBO(src, GR_GL_READ_FRAMEBUFFER, &srcVP, |
| 2716 kSrc_TempFBOTarget); |
| 2717 // We modified the bound FBO |
| 2718 fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; |
| 2719 GrGLIRect srcGLRect; |
| 2720 GrGLIRect dstGLRect; |
| 2721 srcGLRect.setRelativeTo(srcVP, |
| 2722 srcRect.fLeft, |
| 2723 srcRect.fTop, |
| 2724 srcRect.width(), |
| 2725 srcRect.height(), |
| 2726 src->origin()); |
| 2727 dstGLRect.setRelativeTo(dstVP, |
| 2728 dstRect.fLeft, |
| 2729 dstRect.fTop, |
| 2730 dstRect.width(), |
| 2731 dstRect.height(), |
| 2732 dst->origin()); |
| 2733 |
| 2734 // BlitFrameBuffer respects the scissor, so disable it. |
| 2735 this->disableScissor(); |
| 2736 |
| 2737 GrGLint srcY0; |
| 2738 GrGLint srcY1; |
| 2739 // Does the blit need to y-mirror or not? |
| 2740 if (src->origin() == dst->origin()) { |
| 2741 srcY0 = srcGLRect.fBottom; |
| 2742 srcY1 = srcGLRect.fBottom + srcGLRect.fHeight; |
| 2743 } else { |
| 2744 srcY0 = srcGLRect.fBottom + srcGLRect.fHeight; |
| 2745 srcY1 = srcGLRect.fBottom; |
| 2746 } |
| 2747 GL_CALL(BlitFramebuffer(srcGLRect.fLeft, |
| 2748 srcY0, |
| 2749 srcGLRect.fLeft + srcGLRect.fWidth, |
| 2750 srcY1, |
| 2751 dstGLRect.fLeft, |
| 2752 dstGLRect.fBottom, |
| 2753 dstGLRect.fLeft + dstGLRect.fWidth, |
| 2754 dstGLRect.fBottom + dstGLRect.fHeight, |
| 2755 GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST)); |
| 2756 if (dstFBO) { |
| 2757 this->unbindTextureFromFBO(GR_GL_DRAW_FRAMEBUFFER); |
| 2758 } |
| 2759 if (srcFBO) { |
| 2760 this->unbindTextureFromFBO(GR_GL_READ_FRAMEBUFFER); |
| 2761 } |
| 2762 copied = true; |
| 2763 } |
| 2764 } |
| 2765 return copied; |
| 2766 } |
| 2767 |
| 2768 bool GrGLGpu::canCopySurface(const GrSurface* dst, |
| 2769 const GrSurface* src, |
| 2770 const SkIRect& srcRect, |
| 2771 const SkIPoint& dstPoint) { |
| 2772 // This mirrors the logic in onCopySurface. |
| 2773 if (can_copy_texsubimage(dst, src, this)) { |
| 2688 return true; | 2774 return true; |
| 2689 } | 2775 } |
| 2690 | 2776 if (can_blit_framebuffer(dst, src, this)) { |
| 2691 if (can_copy_texsubimage(dst, src, this)) { | 2777 if (dst == src) { |
| 2692 this->copySurfaceAsCopyTexSubImage(dst, src, srcRect, dstPoint); | 2778 SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, |
| 2693 return true; | 2779 srcRect.width(), srcRect.height(
)); |
| 2780 if(!SkIRect::IntersectsNoEmptyCheck(dstRect, srcRect)) { |
| 2781 return true; |
| 2782 } |
| 2783 } else { |
| 2784 return true; |
| 2785 } |
| 2694 } | 2786 } |
| 2695 | |
| 2696 if (can_blit_framebuffer(dst, src, this)) { | |
| 2697 return this->copySurfaceAsBlitFramebuffer(dst, src, srcRect, dstPoint); | |
| 2698 } | |
| 2699 | |
| 2700 return false; | 2787 return false; |
| 2701 } | 2788 } |
| 2702 | 2789 |
| 2703 | |
| 2704 void GrGLGpu::createCopyProgram() { | |
| 2705 const char* version = GrGetGLSLVersionDecl(this->ctxInfo()); | |
| 2706 | |
| 2707 GrGLShaderVar aVertex("a_vertex", kVec2f_GrSLType, GrShaderVar::kAttribute_T
ypeModifier); | |
| 2708 GrGLShaderVar uTexCoordXform("u_texCoordXform", kVec4f_GrSLType, | |
| 2709 GrShaderVar::kUniform_TypeModifier); | |
| 2710 GrGLShaderVar uPosXform("u_posXform", kVec4f_GrSLType, GrShaderVar::kUniform
_TypeModifier); | |
| 2711 GrGLShaderVar uTexture("u_texture", kSampler2D_GrSLType, GrShaderVar::kUnifo
rm_TypeModifier); | |
| 2712 GrGLShaderVar vTexCoord("v_texCoord", kVec2f_GrSLType, GrShaderVar::kVarying
Out_TypeModifier); | |
| 2713 GrGLShaderVar oFragColor("o_FragColor", kVec4f_GrSLType, GrShaderVar::kOut_T
ypeModifier); | |
| 2714 | |
| 2715 SkString vshaderTxt(version); | |
| 2716 aVertex.appendDecl(this->ctxInfo(), &vshaderTxt); | |
| 2717 vshaderTxt.append(";"); | |
| 2718 uTexCoordXform.appendDecl(this->ctxInfo(), &vshaderTxt); | |
| 2719 vshaderTxt.append(";"); | |
| 2720 uPosXform.appendDecl(this->ctxInfo(), &vshaderTxt); | |
| 2721 vshaderTxt.append(";"); | |
| 2722 vTexCoord.appendDecl(this->ctxInfo(), &vshaderTxt); | |
| 2723 vshaderTxt.append(";"); | |
| 2724 | |
| 2725 vshaderTxt.append( | |
| 2726 "// Copy Program VS\n" | |
| 2727 "void main() {" | |
| 2728 " v_texCoord = a_vertex.xy * u_texCoordXform.xy + u_texCoordXform.zw;" | |
| 2729 " gl_Position.xy = a_vertex * u_posXform.xy + u_posXform.zw;" | |
| 2730 " gl_Position.zw = vec2(0, 1);" | |
| 2731 "}" | |
| 2732 ); | |
| 2733 | |
| 2734 SkString fshaderTxt(version); | |
| 2735 GrGLSLAppendDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision, this->g
lStandard(), | |
| 2736 &fshaderTxt); | |
| 2737 vTexCoord.setTypeModifier(GrShaderVar::kVaryingIn_TypeModifier); | |
| 2738 vTexCoord.appendDecl(this->ctxInfo(), &fshaderTxt); | |
| 2739 fshaderTxt.append(";"); | |
| 2740 uTexture.appendDecl(this->ctxInfo(), &fshaderTxt); | |
| 2741 fshaderTxt.append(";"); | |
| 2742 const char* fsOutName; | |
| 2743 if (this->glCaps().glslCaps()->mustDeclareFragmentShaderOutput()) { | |
| 2744 oFragColor.appendDecl(this->ctxInfo(), &fshaderTxt); | |
| 2745 fshaderTxt.append(";"); | |
| 2746 fsOutName = oFragColor.c_str(); | |
| 2747 } else { | |
| 2748 fsOutName = "gl_FragColor"; | |
| 2749 } | |
| 2750 fshaderTxt.appendf( | |
| 2751 "// Copy Program FS\n" | |
| 2752 "void main() {" | |
| 2753 " %s = %s(u_texture, v_texCoord);" | |
| 2754 "}", | |
| 2755 fsOutName, | |
| 2756 GrGLSLTexture2DFunctionName(kVec2f_GrSLType, this->glslGeneration()) | |
| 2757 ); | |
| 2758 | |
| 2759 GL_CALL_RET(fCopyProgram.fProgram, CreateProgram()); | |
| 2760 const char* str; | |
| 2761 GrGLint length; | |
| 2762 | |
| 2763 str = vshaderTxt.c_str(); | |
| 2764 length = SkToInt(vshaderTxt.size()); | |
| 2765 GrGLuint vshader = GrGLCompileAndAttachShader(fGLContext, fCopyProgram.fProg
ram, | |
| 2766 GR_GL_VERTEX_SHADER, &str, &le
ngth, 1, &fStats); | |
| 2767 | |
| 2768 str = fshaderTxt.c_str(); | |
| 2769 length = SkToInt(fshaderTxt.size()); | |
| 2770 GrGLuint fshader = GrGLCompileAndAttachShader(fGLContext, fCopyProgram.fProg
ram, | |
| 2771 GR_GL_FRAGMENT_SHADER, &str, &
length, 1, &fStats); | |
| 2772 | |
| 2773 GL_CALL(LinkProgram(fCopyProgram.fProgram)); | |
| 2774 | |
| 2775 GL_CALL_RET(fCopyProgram.fTextureUniform, GetUniformLocation(fCopyProgram.fP
rogram, | |
| 2776 "u_texture")); | |
| 2777 GL_CALL_RET(fCopyProgram.fPosXformUniform, GetUniformLocation(fCopyProgram.f
Program, | |
| 2778 "u_posXform"))
; | |
| 2779 GL_CALL_RET(fCopyProgram.fTexCoordXformUniform, GetUniformLocation(fCopyProg
ram.fProgram, | |
| 2780 "u_texCoo
rdXform")); | |
| 2781 | |
| 2782 GL_CALL(BindAttribLocation(fCopyProgram.fProgram, 0, "a_vertex")); | |
| 2783 | |
| 2784 GL_CALL(DeleteShader(vshader)); | |
| 2785 GL_CALL(DeleteShader(fshader)); | |
| 2786 | |
| 2787 GL_CALL(GenBuffers(1, &fCopyProgram.fArrayBuffer)); | |
| 2788 fHWGeometryState.setVertexBufferID(this, fCopyProgram.fArrayBuffer); | |
| 2789 static const GrGLfloat vdata[] = { | |
| 2790 0, 0, | |
| 2791 0, 1, | |
| 2792 1, 0, | |
| 2793 1, 1 | |
| 2794 }; | |
| 2795 GL_ALLOC_CALL(this->glInterface(), | |
| 2796 BufferData(GR_GL_ARRAY_BUFFER, | |
| 2797 (GrGLsizeiptr) sizeof(vdata), | |
| 2798 vdata, // data ptr | |
| 2799 GR_GL_STATIC_DRAW)); | |
| 2800 } | |
| 2801 | |
| 2802 void GrGLGpu::copySurfaceAsDraw(GrSurface* dst, | |
| 2803 GrSurface* src, | |
| 2804 const SkIRect& srcRect, | |
| 2805 const SkIPoint& dstPoint) { | |
| 2806 int w = srcRect.width(); | |
| 2807 int h = srcRect.height(); | |
| 2808 | |
| 2809 GrGLTexture* srcTex = static_cast<GrGLTexture*>(src->asTexture()); | |
| 2810 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kNone_Fil
terMode); | |
| 2811 this->bindTexture(0, params, srcTex); | |
| 2812 | |
| 2813 GrGLRenderTarget* dstRT = static_cast<GrGLRenderTarget*>(dst->asRenderTarget
()); | |
| 2814 SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, w, h); | |
| 2815 this->flushRenderTarget(dstRT, &dstRect); | |
| 2816 | |
| 2817 GL_CALL(UseProgram(fCopyProgram.fProgram)); | |
| 2818 fHWProgramID = fCopyProgram.fProgram; | |
| 2819 | |
| 2820 fHWGeometryState.setVertexArrayID(this, 0); | |
| 2821 | |
| 2822 GrGLAttribArrayState* attribs = | |
| 2823 fHWGeometryState.bindArrayAndBufferToDraw(this, fCopyProgram.fArrayBuffe
r); | |
| 2824 attribs->set(this, 0, fCopyProgram.fArrayBuffer, 2, GR_GL_FLOAT, false, | |
| 2825 2 * sizeof(GrGLfloat), 0); | |
| 2826 | |
| 2827 | |
| 2828 // dst rect edges in NDC (-1 to 1) | |
| 2829 int dw = dst->width(); | |
| 2830 int dh = dst->height(); | |
| 2831 GrGLfloat dx0 = 2.f * dstPoint.fX / dw - 1.f; | |
| 2832 GrGLfloat dx1 = 2.f * (dstPoint.fX + w) / dw - 1.f; | |
| 2833 GrGLfloat dy0 = 2.f * dstPoint.fY / dh - 1.f; | |
| 2834 GrGLfloat dy1 = 2.f * (dstPoint.fY + h) / dh - 1.f; | |
| 2835 if (kBottomLeft_GrSurfaceOrigin == dst->origin()) { | |
| 2836 dy0 = -dy0; | |
| 2837 dy1 = -dy1; | |
| 2838 } | |
| 2839 | |
| 2840 // src rect edges in normalized texture space (0 to 1) | |
| 2841 int sw = src->width(); | |
| 2842 int sh = src->height(); | |
| 2843 GrGLfloat sx0 = (GrGLfloat)srcRect.fLeft / sw; | |
| 2844 GrGLfloat sx1 = (GrGLfloat)(srcRect.fLeft + w) / sw; | |
| 2845 GrGLfloat sy0 = (GrGLfloat)srcRect.fTop / sh; | |
| 2846 GrGLfloat sy1 = (GrGLfloat)(srcRect.fTop + h) / sh; | |
| 2847 if (kBottomLeft_GrSurfaceOrigin == src->origin()) { | |
| 2848 sy0 = 1.f - sy0; | |
| 2849 sy1 = 1.f - sy1; | |
| 2850 } | |
| 2851 | |
| 2852 GL_CALL(Uniform4f(fCopyProgram.fPosXformUniform, dx1 - dx0, dy1 - dy0, dx0,
dy0)); | |
| 2853 GL_CALL(Uniform4f(fCopyProgram.fTexCoordXformUniform, sx1 - sx0, sy1 - sy0,
sx0, sy0)); | |
| 2854 GL_CALL(Uniform1i(fCopyProgram.fTextureUniform, 0)); | |
| 2855 | |
| 2856 GrXferProcessor::BlendInfo blendInfo; | |
| 2857 blendInfo.reset(); | |
| 2858 this->flushBlend(blendInfo); | |
| 2859 this->flushColorWrite(true); | |
| 2860 this->flushDither(false); | |
| 2861 this->flushDrawFace(GrPipelineBuilder::kBoth_DrawFace); | |
| 2862 this->flushHWAAState(dstRT, false); | |
| 2863 this->disableScissor(); | |
| 2864 GrStencilSettings stencil; | |
| 2865 stencil.setDisabled(); | |
| 2866 this->flushStencil(stencil); | |
| 2867 | |
| 2868 GL_CALL(DrawArrays(GR_GL_TRIANGLE_STRIP, 0, 4)); | |
| 2869 } | |
| 2870 | |
| 2871 void GrGLGpu::copySurfaceAsCopyTexSubImage(GrSurface* dst, | |
| 2872 GrSurface* src, | |
| 2873 const SkIRect& srcRect, | |
| 2874 const SkIPoint& dstPoint) { | |
| 2875 SkASSERT(can_copy_texsubimage(dst, src, this)); | |
| 2876 GrGLuint srcFBO; | |
| 2877 GrGLIRect srcVP; | |
| 2878 srcFBO = this->bindSurfaceAsFBO(src, GR_GL_FRAMEBUFFER, &srcVP, kSrc_TempFBO
Target); | |
| 2879 GrGLTexture* dstTex = static_cast<GrGLTexture*>(dst->asTexture()); | |
| 2880 SkASSERT(dstTex); | |
| 2881 // We modified the bound FBO | |
| 2882 fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; | |
| 2883 GrGLIRect srcGLRect; | |
| 2884 srcGLRect.setRelativeTo(srcVP, | |
| 2885 srcRect.fLeft, | |
| 2886 srcRect.fTop, | |
| 2887 srcRect.width(), | |
| 2888 srcRect.height(), | |
| 2889 src->origin()); | |
| 2890 | |
| 2891 this->setScratchTextureUnit(); | |
| 2892 GL_CALL(BindTexture(GR_GL_TEXTURE_2D, dstTex->textureID())); | |
| 2893 GrGLint dstY; | |
| 2894 if (kBottomLeft_GrSurfaceOrigin == dst->origin()) { | |
| 2895 dstY = dst->height() - (dstPoint.fY + srcGLRect.fHeight); | |
| 2896 } else { | |
| 2897 dstY = dstPoint.fY; | |
| 2898 } | |
| 2899 GL_CALL(CopyTexSubImage2D(GR_GL_TEXTURE_2D, 0, | |
| 2900 dstPoint.fX, dstY, | |
| 2901 srcGLRect.fLeft, srcGLRect.fBottom, | |
| 2902 srcGLRect.fWidth, srcGLRect.fHeight)); | |
| 2903 if (srcFBO) { | |
| 2904 this->unbindTextureFromFBO(GR_GL_FRAMEBUFFER); | |
| 2905 } | |
| 2906 } | |
| 2907 | |
| 2908 bool GrGLGpu::copySurfaceAsBlitFramebuffer(GrSurface* dst, | |
| 2909 GrSurface* src, | |
| 2910 const SkIRect& srcRect, | |
| 2911 const SkIPoint& dstPoint) { | |
| 2912 SkASSERT(can_blit_framebuffer(dst, src, this)); | |
| 2913 SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, | |
| 2914 srcRect.width(), srcRect.height()); | |
| 2915 if (dst == src) { | |
| 2916 if (SkIRect::IntersectsNoEmptyCheck(dstRect, srcRect)) { | |
| 2917 return false; | |
| 2918 } | |
| 2919 } | |
| 2920 | |
| 2921 GrGLuint dstFBO; | |
| 2922 GrGLuint srcFBO; | |
| 2923 GrGLIRect dstVP; | |
| 2924 GrGLIRect srcVP; | |
| 2925 dstFBO = this->bindSurfaceAsFBO(dst, GR_GL_DRAW_FRAMEBUFFER, &dstVP, | |
| 2926 kDst_TempFBOTarget); | |
| 2927 srcFBO = this->bindSurfaceAsFBO(src, GR_GL_READ_FRAMEBUFFER, &srcVP, | |
| 2928 kSrc_TempFBOTarget); | |
| 2929 // We modified the bound FBO | |
| 2930 fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; | |
| 2931 GrGLIRect srcGLRect; | |
| 2932 GrGLIRect dstGLRect; | |
| 2933 srcGLRect.setRelativeTo(srcVP, | |
| 2934 srcRect.fLeft, | |
| 2935 srcRect.fTop, | |
| 2936 srcRect.width(), | |
| 2937 srcRect.height(), | |
| 2938 src->origin()); | |
| 2939 dstGLRect.setRelativeTo(dstVP, | |
| 2940 dstRect.fLeft, | |
| 2941 dstRect.fTop, | |
| 2942 dstRect.width(), | |
| 2943 dstRect.height(), | |
| 2944 dst->origin()); | |
| 2945 | |
| 2946 // BlitFrameBuffer respects the scissor, so disable it. | |
| 2947 this->disableScissor(); | |
| 2948 | |
| 2949 GrGLint srcY0; | |
| 2950 GrGLint srcY1; | |
| 2951 // Does the blit need to y-mirror or not? | |
| 2952 if (src->origin() == dst->origin()) { | |
| 2953 srcY0 = srcGLRect.fBottom; | |
| 2954 srcY1 = srcGLRect.fBottom + srcGLRect.fHeight; | |
| 2955 } else { | |
| 2956 srcY0 = srcGLRect.fBottom + srcGLRect.fHeight; | |
| 2957 srcY1 = srcGLRect.fBottom; | |
| 2958 } | |
| 2959 GL_CALL(BlitFramebuffer(srcGLRect.fLeft, | |
| 2960 srcY0, | |
| 2961 srcGLRect.fLeft + srcGLRect.fWidth, | |
| 2962 srcY1, | |
| 2963 dstGLRect.fLeft, | |
| 2964 dstGLRect.fBottom, | |
| 2965 dstGLRect.fLeft + dstGLRect.fWidth, | |
| 2966 dstGLRect.fBottom + dstGLRect.fHeight, | |
| 2967 GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST)); | |
| 2968 if (dstFBO) { | |
| 2969 this->unbindTextureFromFBO(GR_GL_DRAW_FRAMEBUFFER); | |
| 2970 } | |
| 2971 if (srcFBO) { | |
| 2972 this->unbindTextureFromFBO(GR_GL_READ_FRAMEBUFFER); | |
| 2973 } | |
| 2974 return true; | |
| 2975 } | |
| 2976 | |
| 2977 void GrGLGpu::xferBarrier(GrRenderTarget* rt, GrXferBarrierType type) { | 2790 void GrGLGpu::xferBarrier(GrRenderTarget* rt, GrXferBarrierType type) { |
| 2978 switch (type) { | 2791 switch (type) { |
| 2979 case kTexture_GrXferBarrierType: { | 2792 case kTexture_GrXferBarrierType: { |
| 2980 GrGLRenderTarget* glrt = static_cast<GrGLRenderTarget*>(rt); | 2793 GrGLRenderTarget* glrt = static_cast<GrGLRenderTarget*>(rt); |
| 2981 if (glrt->textureFBOID() != glrt->renderFBOID()) { | 2794 if (glrt->textureFBOID() != glrt->renderFBOID()) { |
| 2982 // The render target uses separate storage so no need for glText
ureBarrier. | 2795 // The render target uses separate storage so no need for glText
ureBarrier. |
| 2983 // FIXME: The render target will resolve automatically when its
texture is bound, | 2796 // FIXME: The render target will resolve automatically when its
texture is bound, |
| 2984 // but we could resolve only the bounds that will be read if we
do it here instead. | 2797 // but we could resolve only the bounds that will be read if we
do it here instead. |
| 2985 return; | 2798 return; |
| 2986 } | 2799 } |
| (...skipping 25 matching lines...) Expand all Loading... |
| 3012 if (this->caps()->gpuTracingSupport()) { | 2825 if (this->caps()->gpuTracingSupport()) { |
| 3013 #if GR_FORCE_GPU_TRACE_DEBUGGING | 2826 #if GR_FORCE_GPU_TRACE_DEBUGGING |
| 3014 SkDebugf("Pop trace marker.\n"); | 2827 SkDebugf("Pop trace marker.\n"); |
| 3015 #else | 2828 #else |
| 3016 GL_CALL(PopGroupMarker()); | 2829 GL_CALL(PopGroupMarker()); |
| 3017 #endif | 2830 #endif |
| 3018 } | 2831 } |
| 3019 } | 2832 } |
| 3020 | 2833 |
| 3021 /////////////////////////////////////////////////////////////////////////////// | 2834 /////////////////////////////////////////////////////////////////////////////// |
| 2835 |
| 3022 GrGLAttribArrayState* GrGLGpu::HWGeometryState::bindArrayAndBuffersToDraw( | 2836 GrGLAttribArrayState* GrGLGpu::HWGeometryState::bindArrayAndBuffersToDraw( |
| 3023 GrGLGpu* gpu, | 2837 GrGLGpu* gpu, |
| 3024 const GrGLVertexBuffer* vbuffer, | 2838 const GrGLVertexBuffer* vbuffer, |
| 3025 const GrGLIndexBuffer* ibuffer)
{ | 2839 const GrGLIndexBuffer* ibuffer)
{ |
| 3026 SkASSERT(vbuffer); | 2840 SkASSERT(vbuffer); |
| 3027 GrGLuint vbufferID = vbuffer->bufferID(); | |
| 3028 GrGLuint* ibufferIDPtr = NULL; | |
| 3029 GrGLuint ibufferID; | |
| 3030 if (ibuffer) { | |
| 3031 ibufferID = ibuffer->bufferID(); | |
| 3032 ibufferIDPtr = &ibufferID; | |
| 3033 } | |
| 3034 return this->internalBind(gpu, vbufferID, ibufferIDPtr); | |
| 3035 } | |
| 3036 | |
| 3037 GrGLAttribArrayState* GrGLGpu::HWGeometryState::bindArrayAndBufferToDraw(GrGLGpu
* gpu, | |
| 3038 GrGLuin
t vbufferID) { | |
| 3039 return this->internalBind(gpu, vbufferID, NULL); | |
| 3040 } | |
| 3041 | |
| 3042 GrGLAttribArrayState* GrGLGpu::HWGeometryState::bindArrayAndBuffersToDraw(GrGLGp
u* gpu, | |
| 3043 GrGLui
nt vbufferID, | |
| 3044 GrGLui
nt ibufferID) { | |
| 3045 return this->internalBind(gpu, vbufferID, &ibufferID); | |
| 3046 } | |
| 3047 | |
| 3048 GrGLAttribArrayState* GrGLGpu::HWGeometryState::internalBind(GrGLGpu* gpu, | |
| 3049 GrGLuint vbufferID, | |
| 3050 GrGLuint* ibufferID
) { | |
| 3051 GrGLAttribArrayState* attribState; | 2841 GrGLAttribArrayState* attribState; |
| 3052 | 2842 |
| 3053 if (gpu->glCaps().isCoreProfile() && 0 != vbufferID) { | 2843 // We use a vertex array if we're on a core profile and the verts are in a V
BO. |
| 2844 if (gpu->glCaps().isCoreProfile() && !vbuffer->isCPUBacked()) { |
| 3054 if (!fVBOVertexArray) { | 2845 if (!fVBOVertexArray) { |
| 3055 GrGLuint arrayID; | 2846 GrGLuint arrayID; |
| 3056 GR_GL_CALL(gpu->glInterface(), GenVertexArrays(1, &arrayID)); | 2847 GR_GL_CALL(gpu->glInterface(), GenVertexArrays(1, &arrayID)); |
| 3057 int attrCount = gpu->glCaps().maxVertexAttributes(); | 2848 int attrCount = gpu->glCaps().maxVertexAttributes(); |
| 3058 fVBOVertexArray = SkNEW_ARGS(GrGLVertexArray, (arrayID, attrCount)); | 2849 fVBOVertexArray = SkNEW_ARGS(GrGLVertexArray, (arrayID, attrCount)); |
| 3059 } | 2850 } |
| 3060 if (ibufferID) { | 2851 attribState = fVBOVertexArray->bindWithIndexBuffer(gpu, ibuffer); |
| 3061 attribState = fVBOVertexArray->bindWithIndexBuffer(gpu, *ibufferID); | |
| 3062 } else { | |
| 3063 attribState = fVBOVertexArray->bind(gpu); | |
| 3064 } | |
| 3065 } else { | 2852 } else { |
| 3066 if (ibufferID) { | 2853 if (ibuffer) { |
| 3067 this->setIndexBufferIDOnDefaultVertexArray(gpu, *ibufferID); | 2854 this->setIndexBufferIDOnDefaultVertexArray(gpu, ibuffer->bufferID())
; |
| 3068 } else { | 2855 } else { |
| 3069 this->setVertexArrayID(gpu, 0); | 2856 this->setVertexArrayID(gpu, 0); |
| 3070 } | 2857 } |
| 3071 int attrCount = gpu->glCaps().maxVertexAttributes(); | 2858 int attrCount = gpu->glCaps().maxVertexAttributes(); |
| 3072 if (fDefaultVertexArrayAttribState.count() != attrCount) { | 2859 if (fDefaultVertexArrayAttribState.count() != attrCount) { |
| 3073 fDefaultVertexArrayAttribState.resize(attrCount); | 2860 fDefaultVertexArrayAttribState.resize(attrCount); |
| 3074 } | 2861 } |
| 3075 attribState = &fDefaultVertexArrayAttribState; | 2862 attribState = &fDefaultVertexArrayAttribState; |
| 3076 } | 2863 } |
| 3077 return attribState; | 2864 return attribState; |
| 3078 } | 2865 } |
| OLD | NEW |