gfx/skia/trunk/src/gpu/gl/GrGpuGL.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /*
michael@0 2 * Copyright 2011 Google Inc.
michael@0 3 *
michael@0 4 * Use of this source code is governed by a BSD-style license that can be
michael@0 5 * found in the LICENSE file.
michael@0 6 */
michael@0 7
michael@0 8
michael@0 9 #include "GrGpuGL.h"
michael@0 10 #include "GrGLStencilBuffer.h"
michael@0 11 #include "GrGLPath.h"
michael@0 12 #include "GrGLShaderBuilder.h"
michael@0 13 #include "GrTemplates.h"
michael@0 14 #include "GrTypes.h"
michael@0 15 #include "SkStrokeRec.h"
michael@0 16 #include "SkTemplates.h"
michael@0 17
michael@0 18 #define GL_CALL(X) GR_GL_CALL(this->glInterface(), X)
michael@0 19 #define GL_CALL_RET(RET, X) GR_GL_CALL_RET(this->glInterface(), RET, X)
michael@0 20
michael@0 21 #define SKIP_CACHE_CHECK true
michael@0 22
michael@0 23 #if GR_GL_CHECK_ALLOC_WITH_GET_ERROR
michael@0 24 #define CLEAR_ERROR_BEFORE_ALLOC(iface) GrGLClearErr(iface)
michael@0 25 #define GL_ALLOC_CALL(iface, call) GR_GL_CALL_NOERRCHECK(iface, call)
michael@0 26 #define CHECK_ALLOC_ERROR(iface) GR_GL_GET_ERROR(iface)
michael@0 27 #else
michael@0 28 #define CLEAR_ERROR_BEFORE_ALLOC(iface)
michael@0 29 #define GL_ALLOC_CALL(iface, call) GR_GL_CALL(iface, call)
michael@0 30 #define CHECK_ALLOC_ERROR(iface) GR_GL_NO_ERROR
michael@0 31 #endif
michael@0 32
michael@0 33
michael@0 34 ///////////////////////////////////////////////////////////////////////////////
michael@0 35
michael@0 36 static const GrGLenum gXfermodeCoeff2Blend[] = {
michael@0 37 GR_GL_ZERO,
michael@0 38 GR_GL_ONE,
michael@0 39 GR_GL_SRC_COLOR,
michael@0 40 GR_GL_ONE_MINUS_SRC_COLOR,
michael@0 41 GR_GL_DST_COLOR,
michael@0 42 GR_GL_ONE_MINUS_DST_COLOR,
michael@0 43 GR_GL_SRC_ALPHA,
michael@0 44 GR_GL_ONE_MINUS_SRC_ALPHA,
michael@0 45 GR_GL_DST_ALPHA,
michael@0 46 GR_GL_ONE_MINUS_DST_ALPHA,
michael@0 47 GR_GL_CONSTANT_COLOR,
michael@0 48 GR_GL_ONE_MINUS_CONSTANT_COLOR,
michael@0 49 GR_GL_CONSTANT_ALPHA,
michael@0 50 GR_GL_ONE_MINUS_CONSTANT_ALPHA,
michael@0 51
michael@0 52 // extended blend coeffs
michael@0 53 GR_GL_SRC1_COLOR,
michael@0 54 GR_GL_ONE_MINUS_SRC1_COLOR,
michael@0 55 GR_GL_SRC1_ALPHA,
michael@0 56 GR_GL_ONE_MINUS_SRC1_ALPHA,
michael@0 57 };
michael@0 58
michael@0 59 bool GrGpuGL::BlendCoeffReferencesConstant(GrBlendCoeff coeff) {
michael@0 60 static const bool gCoeffReferencesBlendConst[] = {
michael@0 61 false,
michael@0 62 false,
michael@0 63 false,
michael@0 64 false,
michael@0 65 false,
michael@0 66 false,
michael@0 67 false,
michael@0 68 false,
michael@0 69 false,
michael@0 70 false,
michael@0 71 true,
michael@0 72 true,
michael@0 73 true,
michael@0 74 true,
michael@0 75
michael@0 76 // extended blend coeffs
michael@0 77 false,
michael@0 78 false,
michael@0 79 false,
michael@0 80 false,
michael@0 81 };
michael@0 82 return gCoeffReferencesBlendConst[coeff];
michael@0 83 GR_STATIC_ASSERT(kTotalGrBlendCoeffCount ==
michael@0 84 GR_ARRAY_COUNT(gCoeffReferencesBlendConst));
michael@0 85
michael@0 86 GR_STATIC_ASSERT(0 == kZero_GrBlendCoeff);
michael@0 87 GR_STATIC_ASSERT(1 == kOne_GrBlendCoeff);
michael@0 88 GR_STATIC_ASSERT(2 == kSC_GrBlendCoeff);
michael@0 89 GR_STATIC_ASSERT(3 == kISC_GrBlendCoeff);
michael@0 90 GR_STATIC_ASSERT(4 == kDC_GrBlendCoeff);
michael@0 91 GR_STATIC_ASSERT(5 == kIDC_GrBlendCoeff);
michael@0 92 GR_STATIC_ASSERT(6 == kSA_GrBlendCoeff);
michael@0 93 GR_STATIC_ASSERT(7 == kISA_GrBlendCoeff);
michael@0 94 GR_STATIC_ASSERT(8 == kDA_GrBlendCoeff);
michael@0 95 GR_STATIC_ASSERT(9 == kIDA_GrBlendCoeff);
michael@0 96 GR_STATIC_ASSERT(10 == kConstC_GrBlendCoeff);
michael@0 97 GR_STATIC_ASSERT(11 == kIConstC_GrBlendCoeff);
michael@0 98 GR_STATIC_ASSERT(12 == kConstA_GrBlendCoeff);
michael@0 99 GR_STATIC_ASSERT(13 == kIConstA_GrBlendCoeff);
michael@0 100
michael@0 101 GR_STATIC_ASSERT(14 == kS2C_GrBlendCoeff);
michael@0 102 GR_STATIC_ASSERT(15 == kIS2C_GrBlendCoeff);
michael@0 103 GR_STATIC_ASSERT(16 == kS2A_GrBlendCoeff);
michael@0 104 GR_STATIC_ASSERT(17 == kIS2A_GrBlendCoeff);
michael@0 105
michael@0 106 // assertion for gXfermodeCoeff2Blend have to be in GrGpu scope
michael@0 107 GR_STATIC_ASSERT(kTotalGrBlendCoeffCount ==
michael@0 108 GR_ARRAY_COUNT(gXfermodeCoeff2Blend));
michael@0 109 }
michael@0 110
michael@0 111 ///////////////////////////////////////////////////////////////////////////////
michael@0 112
michael@0 113 static bool gPrintStartupSpew;
michael@0 114
michael@0 115 GrGpuGL::GrGpuGL(const GrGLContext& ctx, GrContext* context)
michael@0 116 : GrGpu(context)
michael@0 117 , fGLContext(ctx) {
michael@0 118
michael@0 119 SkASSERT(ctx.isInitialized());
michael@0 120 fCaps.reset(SkRef(ctx.caps()));
michael@0 121
michael@0 122 fHWBoundTextures.reset(this->glCaps().maxFragmentTextureUnits());
michael@0 123 fHWTexGenSettings.reset(this->glCaps().maxFixedFunctionTextureCoords());
michael@0 124
michael@0 125 GrGLClearErr(fGLContext.interface());
michael@0 126 if (gPrintStartupSpew) {
michael@0 127 const GrGLubyte* vendor;
michael@0 128 const GrGLubyte* renderer;
michael@0 129 const GrGLubyte* version;
michael@0 130 GL_CALL_RET(vendor, GetString(GR_GL_VENDOR));
michael@0 131 GL_CALL_RET(renderer, GetString(GR_GL_RENDERER));
michael@0 132 GL_CALL_RET(version, GetString(GR_GL_VERSION));
michael@0 133 GrPrintf("------------------------- create GrGpuGL %p --------------\n",
michael@0 134 this);
michael@0 135 GrPrintf("------ VENDOR %s\n", vendor);
michael@0 136 GrPrintf("------ RENDERER %s\n", renderer);
michael@0 137 GrPrintf("------ VERSION %s\n", version);
michael@0 138 GrPrintf("------ EXTENSIONS\n");
michael@0 139 #if 0 // TODO: Reenable this after GrGLInterface's extensions can be accessed safely.
michael@0 140 ctx.extensions().print();
michael@0 141 #endif
michael@0 142 GrPrintf("\n");
michael@0 143 GrPrintf(this->glCaps().dump().c_str());
michael@0 144 }
michael@0 145
michael@0 146 fProgramCache = SkNEW_ARGS(ProgramCache, (this));
michael@0 147
michael@0 148 SkASSERT(this->glCaps().maxVertexAttributes() >= GrDrawState::kMaxVertexAttribCnt);
michael@0 149
michael@0 150 fLastSuccessfulStencilFmtIdx = 0;
michael@0 151 fHWProgramID = 0;
michael@0 152 }
michael@0 153
michael@0 154 GrGpuGL::~GrGpuGL() {
michael@0 155 if (0 != fHWProgramID) {
michael@0 156 // detach the current program so there is no confusion on OpenGL's part
michael@0 157 // that we want it to be deleted
michael@0 158 SkASSERT(fHWProgramID == fCurrentProgram->programID());
michael@0 159 GL_CALL(UseProgram(0));
michael@0 160 }
michael@0 161
michael@0 162 delete fProgramCache;
michael@0 163
michael@0 164 // This must be called by before the GrDrawTarget destructor
michael@0 165 this->releaseGeometry();
michael@0 166 // This subclass must do this before the base class destructor runs
michael@0 167 // since we will unref the GrGLInterface.
michael@0 168 this->releaseResources();
michael@0 169 }
michael@0 170
michael@0 171 ///////////////////////////////////////////////////////////////////////////////
michael@0 172
michael@0 173
michael@0 174 GrPixelConfig GrGpuGL::preferredReadPixelsConfig(GrPixelConfig readConfig,
michael@0 175 GrPixelConfig surfaceConfig) const {
michael@0 176 if (GR_GL_RGBA_8888_PIXEL_OPS_SLOW && kRGBA_8888_GrPixelConfig == readConfig) {
michael@0 177 return kBGRA_8888_GrPixelConfig;
michael@0 178 } else if (this->glContext().isMesa() &&
michael@0 179 GrBytesPerPixel(readConfig) == 4 &&
michael@0 180 GrPixelConfigSwapRAndB(readConfig) == surfaceConfig) {
michael@0 181 // Mesa 3D takes a slow path on when reading back BGRA from an RGBA surface and vice-versa.
michael@0 182 // Perhaps this should be guarded by some compiletime or runtime check.
michael@0 183 return surfaceConfig;
michael@0 184 } else if (readConfig == kBGRA_8888_GrPixelConfig &&
michael@0 185 !this->glCaps().readPixelsSupported(this->glInterface(),
michael@0 186 GR_GL_BGRA, GR_GL_UNSIGNED_BYTE)) {
michael@0 187 return kRGBA_8888_GrPixelConfig;
michael@0 188 } else {
michael@0 189 return readConfig;
michael@0 190 }
michael@0 191 }
michael@0 192
michael@0 193 GrPixelConfig GrGpuGL::preferredWritePixelsConfig(GrPixelConfig writeConfig,
michael@0 194 GrPixelConfig surfaceConfig) const {
michael@0 195 if (GR_GL_RGBA_8888_PIXEL_OPS_SLOW && kRGBA_8888_GrPixelConfig == writeConfig) {
michael@0 196 return kBGRA_8888_GrPixelConfig;
michael@0 197 } else {
michael@0 198 return writeConfig;
michael@0 199 }
michael@0 200 }
michael@0 201
michael@0 202 bool GrGpuGL::canWriteTexturePixels(const GrTexture* texture, GrPixelConfig srcConfig) const {
michael@0 203 if (kIndex_8_GrPixelConfig == srcConfig || kIndex_8_GrPixelConfig == texture->config()) {
michael@0 204 return false;
michael@0 205 }
michael@0 206 if (srcConfig != texture->config() && kGLES_GrGLStandard == this->glStandard()) {
michael@0 207 // In general ES2 requires the internal format of the texture and the format of the src
michael@0 208 // pixels to match. However, It may or may not be possible to upload BGRA data to a RGBA
michael@0 209 // texture. It depends upon which extension added BGRA. The Apple extension allows it
michael@0 210 // (BGRA's internal format is RGBA) while the EXT extension does not (BGRA is its own
michael@0 211 // internal format).
michael@0 212 if (this->glCaps().bgraFormatSupport() &&
michael@0 213 !this->glCaps().bgraIsInternalFormat() &&
michael@0 214 kBGRA_8888_GrPixelConfig == srcConfig &&
michael@0 215 kRGBA_8888_GrPixelConfig == texture->config()) {
michael@0 216 return true;
michael@0 217 } else {
michael@0 218 return false;
michael@0 219 }
michael@0 220 } else {
michael@0 221 return true;
michael@0 222 }
michael@0 223 }
michael@0 224
michael@0 225 bool GrGpuGL::fullReadPixelsIsFasterThanPartial() const {
michael@0 226 return SkToBool(GR_GL_FULL_READPIXELS_FASTER_THAN_PARTIAL);
michael@0 227 }
michael@0 228
michael@0 229 void GrGpuGL::onResetContext(uint32_t resetBits) {
michael@0 230 // we don't use the zb at all
michael@0 231 if (resetBits & kMisc_GrGLBackendState) {
michael@0 232 GL_CALL(Disable(GR_GL_DEPTH_TEST));
michael@0 233 GL_CALL(DepthMask(GR_GL_FALSE));
michael@0 234
michael@0 235 fHWDrawFace = GrDrawState::kInvalid_DrawFace;
michael@0 236 fHWDitherEnabled = kUnknown_TriState;
michael@0 237
michael@0 238 if (kGL_GrGLStandard == this->glStandard()) {
michael@0 239 // Desktop-only state that we never change
michael@0 240 if (!this->glCaps().isCoreProfile()) {
michael@0 241 GL_CALL(Disable(GR_GL_POINT_SMOOTH));
michael@0 242 GL_CALL(Disable(GR_GL_LINE_SMOOTH));
michael@0 243 GL_CALL(Disable(GR_GL_POLYGON_SMOOTH));
michael@0 244 GL_CALL(Disable(GR_GL_POLYGON_STIPPLE));
michael@0 245 GL_CALL(Disable(GR_GL_COLOR_LOGIC_OP));
michael@0 246 GL_CALL(Disable(GR_GL_INDEX_LOGIC_OP));
michael@0 247 }
michael@0 248 // The windows NVIDIA driver has GL_ARB_imaging in the extension string when using a
michael@0 249 // core profile. This seems like a bug since the core spec removes any mention of
michael@0 250 // GL_ARB_imaging.
michael@0 251 if (this->glCaps().imagingSupport() && !this->glCaps().isCoreProfile()) {
michael@0 252 GL_CALL(Disable(GR_GL_COLOR_TABLE));
michael@0 253 }
michael@0 254 GL_CALL(Disable(GR_GL_POLYGON_OFFSET_FILL));
michael@0 255 // Since ES doesn't support glPointSize at all we always use the VS to
michael@0 256 // set the point size
michael@0 257 GL_CALL(Enable(GR_GL_VERTEX_PROGRAM_POINT_SIZE));
michael@0 258
michael@0 259 // We should set glPolygonMode(FRONT_AND_BACK,FILL) here, too. It isn't
michael@0 260 // currently part of our gl interface. There are probably others as
michael@0 261 // well.
michael@0 262 }
michael@0 263 fHWWriteToColor = kUnknown_TriState;
michael@0 264 // we only ever use lines in hairline mode
michael@0 265 GL_CALL(LineWidth(1));
michael@0 266 }
michael@0 267
michael@0 268 if (resetBits & kAA_GrGLBackendState) {
michael@0 269 fHWAAState.invalidate();
michael@0 270 }
michael@0 271
michael@0 272 fHWActiveTextureUnitIdx = -1; // invalid
michael@0 273
michael@0 274 if (resetBits & kTextureBinding_GrGLBackendState) {
michael@0 275 for (int s = 0; s < fHWBoundTextures.count(); ++s) {
michael@0 276 fHWBoundTextures[s] = NULL;
michael@0 277 }
michael@0 278 }
michael@0 279
michael@0 280 if (resetBits & kBlend_GrGLBackendState) {
michael@0 281 fHWBlendState.invalidate();
michael@0 282 }
michael@0 283
michael@0 284 if (resetBits & kView_GrGLBackendState) {
michael@0 285 fHWScissorSettings.invalidate();
michael@0 286 fHWViewport.invalidate();
michael@0 287 }
michael@0 288
michael@0 289 if (resetBits & kStencil_GrGLBackendState) {
michael@0 290 fHWStencilSettings.invalidate();
michael@0 291 fHWStencilTestEnabled = kUnknown_TriState;
michael@0 292 }
michael@0 293
michael@0 294 // Vertex
michael@0 295 if (resetBits & kVertex_GrGLBackendState) {
michael@0 296 fHWGeometryState.invalidate();
michael@0 297 }
michael@0 298
michael@0 299 if (resetBits & kRenderTarget_GrGLBackendState) {
michael@0 300 fHWBoundRenderTarget = NULL;
michael@0 301 }
michael@0 302
michael@0 303 if (resetBits & (kFixedFunction_GrGLBackendState | kPathRendering_GrGLBackendState)) {
michael@0 304 if (this->glCaps().fixedFunctionSupport()) {
michael@0 305 fHWProjectionMatrixState.invalidate();
michael@0 306 // we don't use the model view matrix.
michael@0 307 GL_CALL(MatrixMode(GR_GL_MODELVIEW));
michael@0 308 GL_CALL(LoadIdentity());
michael@0 309
michael@0 310 for (int i = 0; i < this->glCaps().maxFixedFunctionTextureCoords(); ++i) {
michael@0 311 GL_CALL(ActiveTexture(GR_GL_TEXTURE0 + i));
michael@0 312 GL_CALL(Disable(GR_GL_TEXTURE_GEN_S));
michael@0 313 GL_CALL(Disable(GR_GL_TEXTURE_GEN_T));
michael@0 314 GL_CALL(Disable(GR_GL_TEXTURE_GEN_Q));
michael@0 315 GL_CALL(Disable(GR_GL_TEXTURE_GEN_R));
michael@0 316 if (this->caps()->pathRenderingSupport()) {
michael@0 317 GL_CALL(PathTexGen(GR_GL_TEXTURE0 + i, GR_GL_NONE, 0, NULL));
michael@0 318 }
michael@0 319 fHWTexGenSettings[i].fMode = GR_GL_NONE;
michael@0 320 fHWTexGenSettings[i].fNumComponents = 0;
michael@0 321 }
michael@0 322 fHWActiveTexGenSets = 0;
michael@0 323 }
michael@0 324 if (this->caps()->pathRenderingSupport()) {
michael@0 325 fHWPathStencilSettings.invalidate();
michael@0 326 }
michael@0 327 }
michael@0 328
michael@0 329 // we assume these values
michael@0 330 if (resetBits & kPixelStore_GrGLBackendState) {
michael@0 331 if (this->glCaps().unpackRowLengthSupport()) {
michael@0 332 GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
michael@0 333 }
michael@0 334 if (this->glCaps().packRowLengthSupport()) {
michael@0 335 GL_CALL(PixelStorei(GR_GL_PACK_ROW_LENGTH, 0));
michael@0 336 }
michael@0 337 if (this->glCaps().unpackFlipYSupport()) {
michael@0 338 GL_CALL(PixelStorei(GR_GL_UNPACK_FLIP_Y, GR_GL_FALSE));
michael@0 339 }
michael@0 340 if (this->glCaps().packFlipYSupport()) {
michael@0 341 GL_CALL(PixelStorei(GR_GL_PACK_REVERSE_ROW_ORDER, GR_GL_FALSE));
michael@0 342 }
michael@0 343 }
michael@0 344
michael@0 345 if (resetBits & kProgram_GrGLBackendState) {
michael@0 346 fHWProgramID = 0;
michael@0 347 fSharedGLProgramState.invalidate();
michael@0 348 }
michael@0 349 }
michael@0 350
michael@0 351 namespace {
michael@0 352
michael@0 353 GrSurfaceOrigin resolve_origin(GrSurfaceOrigin origin, bool renderTarget) {
michael@0 354 // By default, GrRenderTargets are GL's normal orientation so that they
michael@0 355 // can be drawn to by the outside world without the client having
michael@0 356 // to render upside down.
michael@0 357 if (kDefault_GrSurfaceOrigin == origin) {
michael@0 358 return renderTarget ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin;
michael@0 359 } else {
michael@0 360 return origin;
michael@0 361 }
michael@0 362 }
michael@0 363
michael@0 364 }
michael@0 365
michael@0 366 GrTexture* GrGpuGL::onWrapBackendTexture(const GrBackendTextureDesc& desc) {
michael@0 367 if (!this->configToGLFormats(desc.fConfig, false, NULL, NULL, NULL)) {
michael@0 368 return NULL;
michael@0 369 }
michael@0 370
michael@0 371 if (0 == desc.fTextureHandle) {
michael@0 372 return NULL;
michael@0 373 }
michael@0 374
michael@0 375 int maxSize = this->caps()->maxTextureSize();
michael@0 376 if (desc.fWidth > maxSize || desc.fHeight > maxSize) {
michael@0 377 return NULL;
michael@0 378 }
michael@0 379
michael@0 380 GrGLTexture::Desc glTexDesc;
michael@0 381 // next line relies on GrBackendTextureDesc's flags matching GrTexture's
michael@0 382 glTexDesc.fFlags = (GrTextureFlags) desc.fFlags;
michael@0 383 glTexDesc.fWidth = desc.fWidth;
michael@0 384 glTexDesc.fHeight = desc.fHeight;
michael@0 385 glTexDesc.fConfig = desc.fConfig;
michael@0 386 glTexDesc.fSampleCnt = desc.fSampleCnt;
michael@0 387 glTexDesc.fTextureID = static_cast<GrGLuint>(desc.fTextureHandle);
michael@0 388 glTexDesc.fIsWrapped = true;
michael@0 389 bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrBackendTextureFlag);
michael@0 390 // FIXME: this should be calling resolve_origin(), but Chrome code is currently
michael@0 391 // assuming the old behaviour, which is that backend textures are always
michael@0 392 // BottomLeft, even for non-RT's. Once Chrome is fixed, change this to:
michael@0 393 // glTexDesc.fOrigin = resolve_origin(desc.fOrigin, renderTarget);
michael@0 394 if (kDefault_GrSurfaceOrigin == desc.fOrigin) {
michael@0 395 glTexDesc.fOrigin = kBottomLeft_GrSurfaceOrigin;
michael@0 396 } else {
michael@0 397 glTexDesc.fOrigin = desc.fOrigin;
michael@0 398 }
michael@0 399
michael@0 400 GrGLTexture* texture = NULL;
michael@0 401 if (renderTarget) {
michael@0 402 GrGLRenderTarget::Desc glRTDesc;
michael@0 403 glRTDesc.fRTFBOID = 0;
michael@0 404 glRTDesc.fTexFBOID = 0;
michael@0 405 glRTDesc.fMSColorRenderbufferID = 0;
michael@0 406 glRTDesc.fConfig = desc.fConfig;
michael@0 407 glRTDesc.fSampleCnt = desc.fSampleCnt;
michael@0 408 glRTDesc.fOrigin = glTexDesc.fOrigin;
michael@0 409 glRTDesc.fCheckAllocation = false;
michael@0 410 if (!this->createRenderTargetObjects(glTexDesc.fWidth,
michael@0 411 glTexDesc.fHeight,
michael@0 412 glTexDesc.fTextureID,
michael@0 413 &glRTDesc)) {
michael@0 414 return NULL;
michael@0 415 }
michael@0 416 texture = SkNEW_ARGS(GrGLTexture, (this, glTexDesc, glRTDesc));
michael@0 417 } else {
michael@0 418 texture = SkNEW_ARGS(GrGLTexture, (this, glTexDesc));
michael@0 419 }
michael@0 420 if (NULL == texture) {
michael@0 421 return NULL;
michael@0 422 }
michael@0 423
michael@0 424 return texture;
michael@0 425 }
michael@0 426
michael@0 427 GrRenderTarget* GrGpuGL::onWrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc) {
michael@0 428 GrGLRenderTarget::Desc glDesc;
michael@0 429 glDesc.fConfig = desc.fConfig;
michael@0 430 glDesc.fRTFBOID = static_cast<GrGLuint>(desc.fRenderTargetHandle);
michael@0 431 glDesc.fMSColorRenderbufferID = 0;
michael@0 432 glDesc.fTexFBOID = GrGLRenderTarget::kUnresolvableFBOID;
michael@0 433 glDesc.fSampleCnt = desc.fSampleCnt;
michael@0 434 glDesc.fIsWrapped = true;
michael@0 435 glDesc.fCheckAllocation = false;
michael@0 436
michael@0 437 glDesc.fOrigin = resolve_origin(desc.fOrigin, true);
michael@0 438 GrGLIRect viewport;
michael@0 439 viewport.fLeft = 0;
michael@0 440 viewport.fBottom = 0;
michael@0 441 viewport.fWidth = desc.fWidth;
michael@0 442 viewport.fHeight = desc.fHeight;
michael@0 443
michael@0 444 GrRenderTarget* tgt = SkNEW_ARGS(GrGLRenderTarget,
michael@0 445 (this, glDesc, viewport));
michael@0 446 if (desc.fStencilBits) {
michael@0 447 GrGLStencilBuffer::Format format;
michael@0 448 format.fInternalFormat = GrGLStencilBuffer::kUnknownInternalFormat;
michael@0 449 format.fPacked = false;
michael@0 450 format.fStencilBits = desc.fStencilBits;
michael@0 451 format.fTotalBits = desc.fStencilBits;
michael@0 452 static const bool kIsSBWrapped = false;
michael@0 453 GrGLStencilBuffer* sb = SkNEW_ARGS(GrGLStencilBuffer,
michael@0 454 (this,
michael@0 455 kIsSBWrapped,
michael@0 456 0,
michael@0 457 desc.fWidth,
michael@0 458 desc.fHeight,
michael@0 459 desc.fSampleCnt,
michael@0 460 format));
michael@0 461 tgt->setStencilBuffer(sb);
michael@0 462 sb->unref();
michael@0 463 }
michael@0 464 return tgt;
michael@0 465 }
michael@0 466
michael@0 467 ////////////////////////////////////////////////////////////////////////////////
michael@0 468
michael@0 469 bool GrGpuGL::onWriteTexturePixels(GrTexture* texture,
michael@0 470 int left, int top, int width, int height,
michael@0 471 GrPixelConfig config, const void* buffer,
michael@0 472 size_t rowBytes) {
michael@0 473 if (NULL == buffer) {
michael@0 474 return false;
michael@0 475 }
michael@0 476 GrGLTexture* glTex = static_cast<GrGLTexture*>(texture);
michael@0 477
michael@0 478 this->setScratchTextureUnit();
michael@0 479 GL_CALL(BindTexture(GR_GL_TEXTURE_2D, glTex->textureID()));
michael@0 480 GrGLTexture::Desc desc;
michael@0 481 desc.fFlags = glTex->desc().fFlags;
michael@0 482 desc.fWidth = glTex->width();
michael@0 483 desc.fHeight = glTex->height();
michael@0 484 desc.fConfig = glTex->config();
michael@0 485 desc.fSampleCnt = glTex->desc().fSampleCnt;
michael@0 486 desc.fTextureID = glTex->textureID();
michael@0 487 desc.fOrigin = glTex->origin();
michael@0 488
michael@0 489 if (this->uploadTexData(desc, false,
michael@0 490 left, top, width, height,
michael@0 491 config, buffer, rowBytes)) {
michael@0 492 texture->dirtyMipMaps(true);
michael@0 493 return true;
michael@0 494 } else {
michael@0 495 return false;
michael@0 496 }
michael@0 497 }
michael@0 498
michael@0 499 namespace {
michael@0 500 bool adjust_pixel_ops_params(int surfaceWidth,
michael@0 501 int surfaceHeight,
michael@0 502 size_t bpp,
michael@0 503 int* left, int* top, int* width, int* height,
michael@0 504 const void** data,
michael@0 505 size_t* rowBytes) {
michael@0 506 if (!*rowBytes) {
michael@0 507 *rowBytes = *width * bpp;
michael@0 508 }
michael@0 509
michael@0 510 SkIRect subRect = SkIRect::MakeXYWH(*left, *top, *width, *height);
michael@0 511 SkIRect bounds = SkIRect::MakeWH(surfaceWidth, surfaceHeight);
michael@0 512
michael@0 513 if (!subRect.intersect(bounds)) {
michael@0 514 return false;
michael@0 515 }
michael@0 516 *data = reinterpret_cast<const void*>(reinterpret_cast<intptr_t>(*data) +
michael@0 517 (subRect.fTop - *top) * *rowBytes + (subRect.fLeft - *left) * bpp);
michael@0 518
michael@0 519 *left = subRect.fLeft;
michael@0 520 *top = subRect.fTop;
michael@0 521 *width = subRect.width();
michael@0 522 *height = subRect.height();
michael@0 523 return true;
michael@0 524 }
michael@0 525
michael@0 526 GrGLenum check_alloc_error(const GrTextureDesc& desc, const GrGLInterface* interface) {
michael@0 527 if (SkToBool(desc.fFlags & kCheckAllocation_GrTextureFlagBit)) {
michael@0 528 return GR_GL_GET_ERROR(interface);
michael@0 529 } else {
michael@0 530 return CHECK_ALLOC_ERROR(interface);
michael@0 531 }
michael@0 532 }
michael@0 533
michael@0 534 }
michael@0 535
michael@0 536 bool GrGpuGL::uploadTexData(const GrGLTexture::Desc& desc,
michael@0 537 bool isNewTexture,
michael@0 538 int left, int top, int width, int height,
michael@0 539 GrPixelConfig dataConfig,
michael@0 540 const void* data,
michael@0 541 size_t rowBytes) {
michael@0 542 SkASSERT(NULL != data || isNewTexture);
michael@0 543
michael@0 544 size_t bpp = GrBytesPerPixel(dataConfig);
michael@0 545 if (!adjust_pixel_ops_params(desc.fWidth, desc.fHeight, bpp, &left, &top,
michael@0 546 &width, &height, &data, &rowBytes)) {
michael@0 547 return false;
michael@0 548 }
michael@0 549 size_t trimRowBytes = width * bpp;
michael@0 550
michael@0 551 // in case we need a temporary, trimmed copy of the src pixels
michael@0 552 SkAutoSMalloc<128 * 128> tempStorage;
michael@0 553
michael@0 554 // paletted textures cannot be partially updated
michael@0 555 // We currently lazily create MIPMAPs when the we see a draw with
michael@0 556 // GrTextureParams::kMipMap_FilterMode. Using texture storage requires that the
michael@0 557 // MIP levels are all created when the texture is created. So for now we don't use
michael@0 558 // texture storage.
michael@0 559 bool useTexStorage = false &&
michael@0 560 isNewTexture &&
michael@0 561 desc.fConfig != kIndex_8_GrPixelConfig &&
michael@0 562 this->glCaps().texStorageSupport();
michael@0 563
michael@0 564 if (useTexStorage && kGL_GrGLStandard == this->glStandard()) {
michael@0 565 // 565 is not a sized internal format on desktop GL. So on desktop with
michael@0 566 // 565 we always use an unsized internal format to let the system pick
michael@0 567 // the best sized format to convert the 565 data to. Since TexStorage
michael@0 568 // only allows sized internal formats we will instead use TexImage2D.
michael@0 569 useTexStorage = desc.fConfig != kRGB_565_GrPixelConfig;
michael@0 570 }
michael@0 571
michael@0 572 GrGLenum internalFormat;
michael@0 573 GrGLenum externalFormat;
michael@0 574 GrGLenum externalType;
michael@0 575 // glTexStorage requires sized internal formats on both desktop and ES. ES2 requires an unsized
michael@0 576 // format for glTexImage, unlike ES3 and desktop. However, we allow the driver to decide the
michael@0 577 // size of the internal format whenever possible and so only use a sized internal format when
michael@0 578 // using texture storage.
michael@0 579 if (!this->configToGLFormats(dataConfig, useTexStorage, &internalFormat,
michael@0 580 &externalFormat, &externalType)) {
michael@0 581 return false;
michael@0 582 }
michael@0 583
michael@0 584 if (!isNewTexture && GR_GL_PALETTE8_RGBA8 == internalFormat) {
michael@0 585 // paletted textures cannot be updated
michael@0 586 return false;
michael@0 587 }
michael@0 588
michael@0 589 /*
michael@0 590 * check whether to allocate a temporary buffer for flipping y or
michael@0 591 * because our srcData has extra bytes past each row. If so, we need
michael@0 592 * to trim those off here, since GL ES may not let us specify
michael@0 593 * GL_UNPACK_ROW_LENGTH.
michael@0 594 */
michael@0 595 bool restoreGLRowLength = false;
michael@0 596 bool swFlipY = false;
michael@0 597 bool glFlipY = false;
michael@0 598 if (NULL != data) {
michael@0 599 if (kBottomLeft_GrSurfaceOrigin == desc.fOrigin) {
michael@0 600 if (this->glCaps().unpackFlipYSupport()) {
michael@0 601 glFlipY = true;
michael@0 602 } else {
michael@0 603 swFlipY = true;
michael@0 604 }
michael@0 605 }
michael@0 606 if (this->glCaps().unpackRowLengthSupport() && !swFlipY) {
michael@0 607 // can't use this for flipping, only non-neg values allowed. :(
michael@0 608 if (rowBytes != trimRowBytes) {
michael@0 609 GrGLint rowLength = static_cast<GrGLint>(rowBytes / bpp);
michael@0 610 GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, rowLength));
michael@0 611 restoreGLRowLength = true;
michael@0 612 }
michael@0 613 } else {
michael@0 614 if (trimRowBytes != rowBytes || swFlipY) {
michael@0 615 // copy data into our new storage, skipping the trailing bytes
michael@0 616 size_t trimSize = height * trimRowBytes;
michael@0 617 const char* src = (const char*)data;
michael@0 618 if (swFlipY) {
michael@0 619 src += (height - 1) * rowBytes;
michael@0 620 }
michael@0 621 char* dst = (char*)tempStorage.reset(trimSize);
michael@0 622 for (int y = 0; y < height; y++) {
michael@0 623 memcpy(dst, src, trimRowBytes);
michael@0 624 if (swFlipY) {
michael@0 625 src -= rowBytes;
michael@0 626 } else {
michael@0 627 src += rowBytes;
michael@0 628 }
michael@0 629 dst += trimRowBytes;
michael@0 630 }
michael@0 631 // now point data to our copied version
michael@0 632 data = tempStorage.get();
michael@0 633 }
michael@0 634 }
michael@0 635 if (glFlipY) {
michael@0 636 GL_CALL(PixelStorei(GR_GL_UNPACK_FLIP_Y, GR_GL_TRUE));
michael@0 637 }
michael@0 638 GL_CALL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, static_cast<GrGLint>(bpp)));
michael@0 639 }
michael@0 640 bool succeeded = true;
michael@0 641 if (isNewTexture &&
michael@0 642 0 == left && 0 == top &&
michael@0 643 desc.fWidth == width && desc.fHeight == height) {
michael@0 644 CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
michael@0 645 if (useTexStorage) {
michael@0 646 // We never resize or change formats of textures.
michael@0 647 GL_ALLOC_CALL(this->glInterface(),
michael@0 648 TexStorage2D(GR_GL_TEXTURE_2D,
michael@0 649 1, // levels
michael@0 650 internalFormat,
michael@0 651 desc.fWidth, desc.fHeight));
michael@0 652 } else {
michael@0 653 if (GR_GL_PALETTE8_RGBA8 == internalFormat) {
michael@0 654 GrGLsizei imageSize = desc.fWidth * desc.fHeight +
michael@0 655 kGrColorTableSize;
michael@0 656 GL_ALLOC_CALL(this->glInterface(),
michael@0 657 CompressedTexImage2D(GR_GL_TEXTURE_2D,
michael@0 658 0, // level
michael@0 659 internalFormat,
michael@0 660 desc.fWidth, desc.fHeight,
michael@0 661 0, // border
michael@0 662 imageSize,
michael@0 663 data));
michael@0 664 } else {
michael@0 665 GL_ALLOC_CALL(this->glInterface(),
michael@0 666 TexImage2D(GR_GL_TEXTURE_2D,
michael@0 667 0, // level
michael@0 668 internalFormat,
michael@0 669 desc.fWidth, desc.fHeight,
michael@0 670 0, // border
michael@0 671 externalFormat, externalType,
michael@0 672 data));
michael@0 673 }
michael@0 674 }
michael@0 675 GrGLenum error = check_alloc_error(desc, this->glInterface());
michael@0 676 if (error != GR_GL_NO_ERROR) {
michael@0 677 succeeded = false;
michael@0 678 } else {
michael@0 679 // if we have data and we used TexStorage to create the texture, we
michael@0 680 // now upload with TexSubImage.
michael@0 681 if (NULL != data && useTexStorage) {
michael@0 682 GL_CALL(TexSubImage2D(GR_GL_TEXTURE_2D,
michael@0 683 0, // level
michael@0 684 left, top,
michael@0 685 width, height,
michael@0 686 externalFormat, externalType,
michael@0 687 data));
michael@0 688 }
michael@0 689 }
michael@0 690 } else {
michael@0 691 if (swFlipY || glFlipY) {
michael@0 692 top = desc.fHeight - (top + height);
michael@0 693 }
michael@0 694 GL_CALL(TexSubImage2D(GR_GL_TEXTURE_2D,
michael@0 695 0, // level
michael@0 696 left, top,
michael@0 697 width, height,
michael@0 698 externalFormat, externalType, data));
michael@0 699 }
michael@0 700
michael@0 701 if (restoreGLRowLength) {
michael@0 702 SkASSERT(this->glCaps().unpackRowLengthSupport());
michael@0 703 GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
michael@0 704 }
michael@0 705 if (glFlipY) {
michael@0 706 GL_CALL(PixelStorei(GR_GL_UNPACK_FLIP_Y, GR_GL_FALSE));
michael@0 707 }
michael@0 708 return succeeded;
michael@0 709 }
michael@0 710
michael@0 711 static bool renderbuffer_storage_msaa(GrGLContext& ctx,
michael@0 712 int sampleCount,
michael@0 713 GrGLenum format,
michael@0 714 int width, int height) {
michael@0 715 CLEAR_ERROR_BEFORE_ALLOC(ctx.interface());
michael@0 716 SkASSERT(GrGLCaps::kNone_MSFBOType != ctx.caps()->msFBOType());
michael@0 717 switch (ctx.caps()->msFBOType()) {
michael@0 718 case GrGLCaps::kDesktop_ARB_MSFBOType:
michael@0 719 case GrGLCaps::kDesktop_EXT_MSFBOType:
michael@0 720 case GrGLCaps::kES_3_0_MSFBOType:
michael@0 721 GL_ALLOC_CALL(ctx.interface(),
michael@0 722 RenderbufferStorageMultisample(GR_GL_RENDERBUFFER,
michael@0 723 sampleCount,
michael@0 724 format,
michael@0 725 width, height));
michael@0 726 break;
michael@0 727 case GrGLCaps::kES_Apple_MSFBOType:
michael@0 728 GL_ALLOC_CALL(ctx.interface(),
michael@0 729 RenderbufferStorageMultisampleES2APPLE(GR_GL_RENDERBUFFER,
michael@0 730 sampleCount,
michael@0 731 format,
michael@0 732 width, height));
michael@0 733 break;
michael@0 734 case GrGLCaps::kES_EXT_MsToTexture_MSFBOType:
michael@0 735 case GrGLCaps::kES_IMG_MsToTexture_MSFBOType:
michael@0 736 GL_ALLOC_CALL(ctx.interface(),
michael@0 737 RenderbufferStorageMultisampleES2EXT(GR_GL_RENDERBUFFER,
michael@0 738 sampleCount,
michael@0 739 format,
michael@0 740 width, height));
michael@0 741 break;
michael@0 742 case GrGLCaps::kNone_MSFBOType:
michael@0 743 GrCrash("Shouldn't be here if we don't support multisampled renderbuffers.");
michael@0 744 break;
michael@0 745 }
michael@0 746 return (GR_GL_NO_ERROR == CHECK_ALLOC_ERROR(ctx.interface()));;
michael@0 747 }
michael@0 748
michael@0 749 bool GrGpuGL::createRenderTargetObjects(int width, int height,
michael@0 750 GrGLuint texID,
michael@0 751 GrGLRenderTarget::Desc* desc) {
michael@0 752 desc->fMSColorRenderbufferID = 0;
michael@0 753 desc->fRTFBOID = 0;
michael@0 754 desc->fTexFBOID = 0;
michael@0 755 desc->fIsWrapped = false;
michael@0 756
michael@0 757 GrGLenum status;
michael@0 758
michael@0 759 GrGLenum msColorFormat = 0; // suppress warning
michael@0 760
michael@0 761 if (desc->fSampleCnt > 0 && GrGLCaps::kNone_MSFBOType == this->glCaps().msFBOType()) {
michael@0 762 goto FAILED;
michael@0 763 }
michael@0 764
michael@0 765 GL_CALL(GenFramebuffers(1, &desc->fTexFBOID));
michael@0 766 if (!desc->fTexFBOID) {
michael@0 767 goto FAILED;
michael@0 768 }
michael@0 769
michael@0 770
michael@0 771 // If we are using multisampling we will create two FBOS. We render to one and then resolve to
michael@0 772 // the texture bound to the other. The exception is the IMG multisample extension. With this
michael@0 773 // extension the texture is multisampled when rendered to and then auto-resolves it when it is
michael@0 774 // rendered from.
michael@0 775 if (desc->fSampleCnt > 0 && this->glCaps().usesMSAARenderBuffers()) {
michael@0 776 GL_CALL(GenFramebuffers(1, &desc->fRTFBOID));
michael@0 777 GL_CALL(GenRenderbuffers(1, &desc->fMSColorRenderbufferID));
michael@0 778 if (!desc->fRTFBOID ||
michael@0 779 !desc->fMSColorRenderbufferID ||
michael@0 780 !this->configToGLFormats(desc->fConfig,
michael@0 781 // ES2 and ES3 require sized internal formats for rb storage.
michael@0 782 kGLES_GrGLStandard == this->glStandard(),
michael@0 783 &msColorFormat,
michael@0 784 NULL,
michael@0 785 NULL)) {
michael@0 786 goto FAILED;
michael@0 787 }
michael@0 788 } else {
michael@0 789 desc->fRTFBOID = desc->fTexFBOID;
michael@0 790 }
michael@0 791
michael@0 792 // below here we may bind the FBO
michael@0 793 fHWBoundRenderTarget = NULL;
michael@0 794 if (desc->fRTFBOID != desc->fTexFBOID) {
michael@0 795 SkASSERT(desc->fSampleCnt > 0);
michael@0 796 GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER,
michael@0 797 desc->fMSColorRenderbufferID));
michael@0 798 if (!renderbuffer_storage_msaa(fGLContext,
michael@0 799 desc->fSampleCnt,
michael@0 800 msColorFormat,
michael@0 801 width, height)) {
michael@0 802 goto FAILED;
michael@0 803 }
michael@0 804 GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, desc->fRTFBOID));
michael@0 805 GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
michael@0 806 GR_GL_COLOR_ATTACHMENT0,
michael@0 807 GR_GL_RENDERBUFFER,
michael@0 808 desc->fMSColorRenderbufferID));
michael@0 809 if (desc->fCheckAllocation ||
michael@0 810 !this->glCaps().isConfigVerifiedColorAttachment(desc->fConfig)) {
michael@0 811 GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
michael@0 812 if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
michael@0 813 goto FAILED;
michael@0 814 }
michael@0 815 fGLContext.caps()->markConfigAsValidColorAttachment(desc->fConfig);
michael@0 816 }
michael@0 817 }
michael@0 818 GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, desc->fTexFBOID));
michael@0 819
michael@0 820 if (this->glCaps().usesImplicitMSAAResolve() && desc->fSampleCnt > 0) {
michael@0 821 GL_CALL(FramebufferTexture2DMultisample(GR_GL_FRAMEBUFFER,
michael@0 822 GR_GL_COLOR_ATTACHMENT0,
michael@0 823 GR_GL_TEXTURE_2D,
michael@0 824 texID, 0, desc->fSampleCnt));
michael@0 825 } else {
michael@0 826 GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER,
michael@0 827 GR_GL_COLOR_ATTACHMENT0,
michael@0 828 GR_GL_TEXTURE_2D,
michael@0 829 texID, 0));
michael@0 830 }
michael@0 831 if (desc->fCheckAllocation ||
michael@0 832 !this->glCaps().isConfigVerifiedColorAttachment(desc->fConfig)) {
michael@0 833 GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
michael@0 834 if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
michael@0 835 goto FAILED;
michael@0 836 }
michael@0 837 fGLContext.caps()->markConfigAsValidColorAttachment(desc->fConfig);
michael@0 838 }
michael@0 839
michael@0 840 return true;
michael@0 841
michael@0 842 FAILED:
michael@0 843 if (desc->fMSColorRenderbufferID) {
michael@0 844 GL_CALL(DeleteRenderbuffers(1, &desc->fMSColorRenderbufferID));
michael@0 845 }
michael@0 846 if (desc->fRTFBOID != desc->fTexFBOID) {
michael@0 847 GL_CALL(DeleteFramebuffers(1, &desc->fRTFBOID));
michael@0 848 }
michael@0 849 if (desc->fTexFBOID) {
michael@0 850 GL_CALL(DeleteFramebuffers(1, &desc->fTexFBOID));
michael@0 851 }
michael@0 852 return false;
michael@0 853 }
michael@0 854
michael@0 855 // good to set a break-point here to know when createTexture fails
michael@0 856 static GrTexture* return_null_texture() {
michael@0 857 // SkDEBUGFAIL("null texture");
michael@0 858 return NULL;
michael@0 859 }
michael@0 860
michael@0 861 #if 0 && defined(SK_DEBUG)
michael@0 862 static size_t as_size_t(int x) {
michael@0 863 return x;
michael@0 864 }
michael@0 865 #endif
michael@0 866
michael@0 867 GrTexture* GrGpuGL::onCreateTexture(const GrTextureDesc& desc,
michael@0 868 const void* srcData,
michael@0 869 size_t rowBytes) {
michael@0 870
michael@0 871 GrGLTexture::Desc glTexDesc;
michael@0 872 GrGLRenderTarget::Desc glRTDesc;
michael@0 873
michael@0 874 // Attempt to catch un- or wrongly initialized sample counts;
michael@0 875 SkASSERT(desc.fSampleCnt >= 0 && desc.fSampleCnt <= 64);
michael@0 876 // We fail if the MSAA was requested and is not available.
michael@0 877 if (GrGLCaps::kNone_MSFBOType == this->glCaps().msFBOType() && desc.fSampleCnt) {
michael@0 878 //GrPrintf("MSAA RT requested but not supported on this platform.");
michael@0 879 return return_null_texture();
michael@0 880 }
michael@0 881 // If the sample count exceeds the max then we clamp it.
michael@0 882 glTexDesc.fSampleCnt = GrMin(desc.fSampleCnt, this->caps()->maxSampleCount());
michael@0 883
michael@0 884 glTexDesc.fFlags = desc.fFlags;
michael@0 885 glTexDesc.fWidth = desc.fWidth;
michael@0 886 glTexDesc.fHeight = desc.fHeight;
michael@0 887 glTexDesc.fConfig = desc.fConfig;
michael@0 888 glTexDesc.fIsWrapped = false;
michael@0 889
michael@0 890 glRTDesc.fMSColorRenderbufferID = 0;
michael@0 891 glRTDesc.fRTFBOID = 0;
michael@0 892 glRTDesc.fTexFBOID = 0;
michael@0 893 glRTDesc.fIsWrapped = false;
michael@0 894 glRTDesc.fConfig = glTexDesc.fConfig;
michael@0 895 glRTDesc.fCheckAllocation = SkToBool(desc.fFlags & kCheckAllocation_GrTextureFlagBit);
michael@0 896
michael@0 897 bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrTextureFlagBit);
michael@0 898
michael@0 899 glTexDesc.fOrigin = resolve_origin(desc.fOrigin, renderTarget);
michael@0 900 glRTDesc.fOrigin = glTexDesc.fOrigin;
michael@0 901
michael@0 902 glRTDesc.fSampleCnt = glTexDesc.fSampleCnt;
michael@0 903 if (GrGLCaps::kNone_MSFBOType == this->glCaps().msFBOType() &&
michael@0 904 desc.fSampleCnt) {
michael@0 905 //GrPrintf("MSAA RT requested but not supported on this platform.");
michael@0 906 return return_null_texture();
michael@0 907 }
michael@0 908
michael@0 909 if (renderTarget) {
michael@0 910 int maxRTSize = this->caps()->maxRenderTargetSize();
michael@0 911 if (glTexDesc.fWidth > maxRTSize || glTexDesc.fHeight > maxRTSize) {
michael@0 912 return return_null_texture();
michael@0 913 }
michael@0 914 } else {
michael@0 915 int maxSize = this->caps()->maxTextureSize();
michael@0 916 if (glTexDesc.fWidth > maxSize || glTexDesc.fHeight > maxSize) {
michael@0 917 return return_null_texture();
michael@0 918 }
michael@0 919 }
michael@0 920
michael@0 921 GL_CALL(GenTextures(1, &glTexDesc.fTextureID));
michael@0 922
michael@0 923 if (!glTexDesc.fTextureID) {
michael@0 924 return return_null_texture();
michael@0 925 }
michael@0 926
michael@0 927 this->setScratchTextureUnit();
michael@0 928 GL_CALL(BindTexture(GR_GL_TEXTURE_2D, glTexDesc.fTextureID));
michael@0 929
michael@0 930 if (renderTarget && this->glCaps().textureUsageSupport()) {
michael@0 931 // provides a hint about how this texture will be used
michael@0 932 GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
michael@0 933 GR_GL_TEXTURE_USAGE,
michael@0 934 GR_GL_FRAMEBUFFER_ATTACHMENT));
michael@0 935 }
michael@0 936
michael@0 937 // Some drivers like to know filter/wrap before seeing glTexImage2D. Some
michael@0 938 // drivers have a bug where an FBO won't be complete if it includes a
michael@0 939 // texture that is not mipmap complete (considering the filter in use).
michael@0 940 GrGLTexture::TexParams initialTexParams;
michael@0 941 // we only set a subset here so invalidate first
michael@0 942 initialTexParams.invalidate();
michael@0 943 initialTexParams.fMinFilter = GR_GL_NEAREST;
michael@0 944 initialTexParams.fMagFilter = GR_GL_NEAREST;
michael@0 945 initialTexParams.fWrapS = GR_GL_CLAMP_TO_EDGE;
michael@0 946 initialTexParams.fWrapT = GR_GL_CLAMP_TO_EDGE;
michael@0 947 GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
michael@0 948 GR_GL_TEXTURE_MAG_FILTER,
michael@0 949 initialTexParams.fMagFilter));
michael@0 950 GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
michael@0 951 GR_GL_TEXTURE_MIN_FILTER,
michael@0 952 initialTexParams.fMinFilter));
michael@0 953 GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
michael@0 954 GR_GL_TEXTURE_WRAP_S,
michael@0 955 initialTexParams.fWrapS));
michael@0 956 GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
michael@0 957 GR_GL_TEXTURE_WRAP_T,
michael@0 958 initialTexParams.fWrapT));
michael@0 959 if (!this->uploadTexData(glTexDesc, true, 0, 0,
michael@0 960 glTexDesc.fWidth, glTexDesc.fHeight,
michael@0 961 desc.fConfig, srcData, rowBytes)) {
michael@0 962 GL_CALL(DeleteTextures(1, &glTexDesc.fTextureID));
michael@0 963 return return_null_texture();
michael@0 964 }
michael@0 965
michael@0 966 GrGLTexture* tex;
michael@0 967 if (renderTarget) {
michael@0 968 // unbind the texture from the texture unit before binding it to the frame buffer
michael@0 969 GL_CALL(BindTexture(GR_GL_TEXTURE_2D, 0));
michael@0 970
michael@0 971 if (!this->createRenderTargetObjects(glTexDesc.fWidth,
michael@0 972 glTexDesc.fHeight,
michael@0 973 glTexDesc.fTextureID,
michael@0 974 &glRTDesc)) {
michael@0 975 GL_CALL(DeleteTextures(1, &glTexDesc.fTextureID));
michael@0 976 return return_null_texture();
michael@0 977 }
michael@0 978 tex = SkNEW_ARGS(GrGLTexture, (this, glTexDesc, glRTDesc));
michael@0 979 } else {
michael@0 980 tex = SkNEW_ARGS(GrGLTexture, (this, glTexDesc));
michael@0 981 }
michael@0 982 tex->setCachedTexParams(initialTexParams, this->getResetTimestamp());
michael@0 983 #ifdef TRACE_TEXTURE_CREATION
michael@0 984 GrPrintf("--- new texture [%d] size=(%d %d) config=%d\n",
michael@0 985 glTexDesc.fTextureID, desc.fWidth, desc.fHeight, desc.fConfig);
michael@0 986 #endif
michael@0 987 return tex;
michael@0 988 }
michael@0 989
michael@0 990 namespace {
michael@0 991
michael@0 992 const GrGLuint kUnknownBitCount = GrGLStencilBuffer::kUnknownBitCount;
michael@0 993
michael@0 994 void inline get_stencil_rb_sizes(const GrGLInterface* gl,
michael@0 995 GrGLStencilBuffer::Format* format) {
michael@0 996
michael@0 997 // we shouldn't ever know one size and not the other
michael@0 998 SkASSERT((kUnknownBitCount == format->fStencilBits) ==
michael@0 999 (kUnknownBitCount == format->fTotalBits));
michael@0 1000 if (kUnknownBitCount == format->fStencilBits) {
michael@0 1001 GR_GL_GetRenderbufferParameteriv(gl, GR_GL_RENDERBUFFER,
michael@0 1002 GR_GL_RENDERBUFFER_STENCIL_SIZE,
michael@0 1003 (GrGLint*)&format->fStencilBits);
michael@0 1004 if (format->fPacked) {
michael@0 1005 GR_GL_GetRenderbufferParameteriv(gl, GR_GL_RENDERBUFFER,
michael@0 1006 GR_GL_RENDERBUFFER_DEPTH_SIZE,
michael@0 1007 (GrGLint*)&format->fTotalBits);
michael@0 1008 format->fTotalBits += format->fStencilBits;
michael@0 1009 } else {
michael@0 1010 format->fTotalBits = format->fStencilBits;
michael@0 1011 }
michael@0 1012 }
michael@0 1013 }
michael@0 1014 }
michael@0 1015
michael@0 1016 bool GrGpuGL::createStencilBufferForRenderTarget(GrRenderTarget* rt,
michael@0 1017 int width, int height) {
michael@0 1018
michael@0 1019 // All internally created RTs are also textures. We don't create
michael@0 1020 // SBs for a client's standalone RT (that is a RT that isn't also a texture).
michael@0 1021 SkASSERT(rt->asTexture());
michael@0 1022 SkASSERT(width >= rt->width());
michael@0 1023 SkASSERT(height >= rt->height());
michael@0 1024
michael@0 1025 int samples = rt->numSamples();
michael@0 1026 GrGLuint sbID;
michael@0 1027 GL_CALL(GenRenderbuffers(1, &sbID));
michael@0 1028 if (!sbID) {
michael@0 1029 return false;
michael@0 1030 }
michael@0 1031
michael@0 1032 int stencilFmtCnt = this->glCaps().stencilFormats().count();
michael@0 1033 for (int i = 0; i < stencilFmtCnt; ++i) {
michael@0 1034 GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, sbID));
michael@0 1035 // we start with the last stencil format that succeeded in hopes
michael@0 1036 // that we won't go through this loop more than once after the
michael@0 1037 // first (painful) stencil creation.
michael@0 1038 int sIdx = (i + fLastSuccessfulStencilFmtIdx) % stencilFmtCnt;
michael@0 1039 const GrGLCaps::StencilFormat& sFmt =
michael@0 1040 this->glCaps().stencilFormats()[sIdx];
michael@0 1041 CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
michael@0 1042 // we do this "if" so that we don't call the multisample
michael@0 1043 // version on a GL that doesn't have an MSAA extension.
michael@0 1044 bool created;
michael@0 1045 if (samples > 0) {
michael@0 1046 created = renderbuffer_storage_msaa(fGLContext,
michael@0 1047 samples,
michael@0 1048 sFmt.fInternalFormat,
michael@0 1049 width, height);
michael@0 1050 } else {
michael@0 1051 GL_ALLOC_CALL(this->glInterface(),
michael@0 1052 RenderbufferStorage(GR_GL_RENDERBUFFER,
michael@0 1053 sFmt.fInternalFormat,
michael@0 1054 width, height));
michael@0 1055 created =
michael@0 1056 (GR_GL_NO_ERROR == check_alloc_error(rt->desc(), this->glInterface()));
michael@0 1057 }
michael@0 1058 if (created) {
michael@0 1059 // After sized formats we attempt an unsized format and take
michael@0 1060 // whatever sizes GL gives us. In that case we query for the size.
michael@0 1061 GrGLStencilBuffer::Format format = sFmt;
michael@0 1062 get_stencil_rb_sizes(this->glInterface(), &format);
michael@0 1063 static const bool kIsWrapped = false;
michael@0 1064 SkAutoTUnref<GrStencilBuffer> sb(SkNEW_ARGS(GrGLStencilBuffer,
michael@0 1065 (this, kIsWrapped, sbID, width, height,
michael@0 1066 samples, format)));
michael@0 1067 if (this->attachStencilBufferToRenderTarget(sb, rt)) {
michael@0 1068 fLastSuccessfulStencilFmtIdx = sIdx;
michael@0 1069 sb->transferToCache();
michael@0 1070 rt->setStencilBuffer(sb);
michael@0 1071 return true;
michael@0 1072 }
michael@0 1073 sb->abandon(); // otherwise we lose sbID
michael@0 1074 }
michael@0 1075 }
michael@0 1076 GL_CALL(DeleteRenderbuffers(1, &sbID));
michael@0 1077 return false;
michael@0 1078 }
michael@0 1079
michael@0 1080 bool GrGpuGL::attachStencilBufferToRenderTarget(GrStencilBuffer* sb, GrRenderTarget* rt) {
michael@0 1081 GrGLRenderTarget* glrt = (GrGLRenderTarget*) rt;
michael@0 1082
michael@0 1083 GrGLuint fbo = glrt->renderFBOID();
michael@0 1084
michael@0 1085 if (NULL == sb) {
michael@0 1086 if (NULL != rt->getStencilBuffer()) {
michael@0 1087 GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
michael@0 1088 GR_GL_STENCIL_ATTACHMENT,
michael@0 1089 GR_GL_RENDERBUFFER, 0));
michael@0 1090 GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
michael@0 1091 GR_GL_DEPTH_ATTACHMENT,
michael@0 1092 GR_GL_RENDERBUFFER, 0));
michael@0 1093 #ifdef SK_DEBUG
michael@0 1094 GrGLenum status;
michael@0 1095 GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
michael@0 1096 SkASSERT(GR_GL_FRAMEBUFFER_COMPLETE == status);
michael@0 1097 #endif
michael@0 1098 }
michael@0 1099 return true;
michael@0 1100 } else {
michael@0 1101 GrGLStencilBuffer* glsb = static_cast<GrGLStencilBuffer*>(sb);
michael@0 1102 GrGLuint rb = glsb->renderbufferID();
michael@0 1103
michael@0 1104 fHWBoundRenderTarget = NULL;
michael@0 1105 GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fbo));
michael@0 1106 GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
michael@0 1107 GR_GL_STENCIL_ATTACHMENT,
michael@0 1108 GR_GL_RENDERBUFFER, rb));
michael@0 1109 if (glsb->format().fPacked) {
michael@0 1110 GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
michael@0 1111 GR_GL_DEPTH_ATTACHMENT,
michael@0 1112 GR_GL_RENDERBUFFER, rb));
michael@0 1113 } else {
michael@0 1114 GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
michael@0 1115 GR_GL_DEPTH_ATTACHMENT,
michael@0 1116 GR_GL_RENDERBUFFER, 0));
michael@0 1117 }
michael@0 1118
michael@0 1119 GrGLenum status;
michael@0 1120 if (!this->glCaps().isColorConfigAndStencilFormatVerified(rt->config(), glsb->format())) {
michael@0 1121 GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
michael@0 1122 if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
michael@0 1123 GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
michael@0 1124 GR_GL_STENCIL_ATTACHMENT,
michael@0 1125 GR_GL_RENDERBUFFER, 0));
michael@0 1126 if (glsb->format().fPacked) {
michael@0 1127 GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
michael@0 1128 GR_GL_DEPTH_ATTACHMENT,
michael@0 1129 GR_GL_RENDERBUFFER, 0));
michael@0 1130 }
michael@0 1131 return false;
michael@0 1132 } else {
michael@0 1133 fGLContext.caps()->markColorConfigAndStencilFormatAsVerified(
michael@0 1134 rt->config(),
michael@0 1135 glsb->format());
michael@0 1136 }
michael@0 1137 }
michael@0 1138 return true;
michael@0 1139 }
michael@0 1140 }
michael@0 1141
michael@0 1142 ////////////////////////////////////////////////////////////////////////////////
michael@0 1143
michael@0 1144 GrVertexBuffer* GrGpuGL::onCreateVertexBuffer(size_t size, bool dynamic) {
michael@0 1145 GrGLVertexBuffer::Desc desc;
michael@0 1146 desc.fDynamic = dynamic;
michael@0 1147 desc.fSizeInBytes = size;
michael@0 1148 desc.fIsWrapped = false;
michael@0 1149
michael@0 1150 if (this->glCaps().useNonVBOVertexAndIndexDynamicData() && desc.fDynamic) {
michael@0 1151 desc.fID = 0;
michael@0 1152 GrGLVertexBuffer* vertexBuffer = SkNEW_ARGS(GrGLVertexBuffer, (this, desc));
michael@0 1153 return vertexBuffer;
michael@0 1154 } else {
michael@0 1155 GL_CALL(GenBuffers(1, &desc.fID));
michael@0 1156 if (desc.fID) {
michael@0 1157 fHWGeometryState.setVertexBufferID(this, desc.fID);
michael@0 1158 CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
michael@0 1159 // make sure driver can allocate memory for this buffer
michael@0 1160 GL_ALLOC_CALL(this->glInterface(),
michael@0 1161 BufferData(GR_GL_ARRAY_BUFFER,
michael@0 1162 (GrGLsizeiptr) desc.fSizeInBytes,
michael@0 1163 NULL, // data ptr
michael@0 1164 desc.fDynamic ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW));
michael@0 1165 if (CHECK_ALLOC_ERROR(this->glInterface()) != GR_GL_NO_ERROR) {
michael@0 1166 GL_CALL(DeleteBuffers(1, &desc.fID));
michael@0 1167 this->notifyVertexBufferDelete(desc.fID);
michael@0 1168 return NULL;
michael@0 1169 }
michael@0 1170 GrGLVertexBuffer* vertexBuffer = SkNEW_ARGS(GrGLVertexBuffer, (this, desc));
michael@0 1171 return vertexBuffer;
michael@0 1172 }
michael@0 1173 return NULL;
michael@0 1174 }
michael@0 1175 }
michael@0 1176
michael@0 1177 GrIndexBuffer* GrGpuGL::onCreateIndexBuffer(size_t size, bool dynamic) {
michael@0 1178 GrGLIndexBuffer::Desc desc;
michael@0 1179 desc.fDynamic = dynamic;
michael@0 1180 desc.fSizeInBytes = size;
michael@0 1181 desc.fIsWrapped = false;
michael@0 1182
michael@0 1183 if (this->glCaps().useNonVBOVertexAndIndexDynamicData() && desc.fDynamic) {
michael@0 1184 desc.fID = 0;
michael@0 1185 GrIndexBuffer* indexBuffer = SkNEW_ARGS(GrGLIndexBuffer, (this, desc));
michael@0 1186 return indexBuffer;
michael@0 1187 } else {
michael@0 1188 GL_CALL(GenBuffers(1, &desc.fID));
michael@0 1189 if (desc.fID) {
michael@0 1190 fHWGeometryState.setIndexBufferIDOnDefaultVertexArray(this, desc.fID);
michael@0 1191 CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
michael@0 1192 // make sure driver can allocate memory for this buffer
michael@0 1193 GL_ALLOC_CALL(this->glInterface(),
michael@0 1194 BufferData(GR_GL_ELEMENT_ARRAY_BUFFER,
michael@0 1195 (GrGLsizeiptr) desc.fSizeInBytes,
michael@0 1196 NULL, // data ptr
michael@0 1197 desc.fDynamic ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW));
michael@0 1198 if (CHECK_ALLOC_ERROR(this->glInterface()) != GR_GL_NO_ERROR) {
michael@0 1199 GL_CALL(DeleteBuffers(1, &desc.fID));
michael@0 1200 this->notifyIndexBufferDelete(desc.fID);
michael@0 1201 return NULL;
michael@0 1202 }
michael@0 1203 GrIndexBuffer* indexBuffer = SkNEW_ARGS(GrGLIndexBuffer, (this, desc));
michael@0 1204 return indexBuffer;
michael@0 1205 }
michael@0 1206 return NULL;
michael@0 1207 }
michael@0 1208 }
michael@0 1209
michael@0 1210 GrPath* GrGpuGL::onCreatePath(const SkPath& inPath, const SkStrokeRec& stroke) {
michael@0 1211 SkASSERT(this->caps()->pathRenderingSupport());
michael@0 1212 return SkNEW_ARGS(GrGLPath, (this, inPath, stroke));
michael@0 1213 }
michael@0 1214
michael@0 1215 void GrGpuGL::flushScissor() {
michael@0 1216 if (fScissorState.fEnabled) {
michael@0 1217 // Only access the RT if scissoring is being enabled. We can call this before performing
michael@0 1218 // a glBitframebuffer for a surface->surface copy, which requires no RT to be bound to the
michael@0 1219 // GrDrawState.
michael@0 1220 const GrDrawState& drawState = this->getDrawState();
michael@0 1221 const GrGLRenderTarget* rt =
michael@0 1222 static_cast<const GrGLRenderTarget*>(drawState.getRenderTarget());
michael@0 1223
michael@0 1224 SkASSERT(NULL != rt);
michael@0 1225 const GrGLIRect& vp = rt->getViewport();
michael@0 1226 GrGLIRect scissor;
michael@0 1227 scissor.setRelativeTo(vp,
michael@0 1228 fScissorState.fRect.fLeft,
michael@0 1229 fScissorState.fRect.fTop,
michael@0 1230 fScissorState.fRect.width(),
michael@0 1231 fScissorState.fRect.height(),
michael@0 1232 rt->origin());
michael@0 1233 // if the scissor fully contains the viewport then we fall through and
michael@0 1234 // disable the scissor test.
michael@0 1235 if (!scissor.contains(vp)) {
michael@0 1236 if (fHWScissorSettings.fRect != scissor) {
michael@0 1237 scissor.pushToGLScissor(this->glInterface());
michael@0 1238 fHWScissorSettings.fRect = scissor;
michael@0 1239 }
michael@0 1240 if (kYes_TriState != fHWScissorSettings.fEnabled) {
michael@0 1241 GL_CALL(Enable(GR_GL_SCISSOR_TEST));
michael@0 1242 fHWScissorSettings.fEnabled = kYes_TriState;
michael@0 1243 }
michael@0 1244 return;
michael@0 1245 }
michael@0 1246 }
michael@0 1247 if (kNo_TriState != fHWScissorSettings.fEnabled) {
michael@0 1248 GL_CALL(Disable(GR_GL_SCISSOR_TEST));
michael@0 1249 fHWScissorSettings.fEnabled = kNo_TriState;
michael@0 1250 return;
michael@0 1251 }
michael@0 1252 }
michael@0 1253
michael@0 1254 void GrGpuGL::onClear(const SkIRect* rect, GrColor color, bool canIgnoreRect) {
michael@0 1255 const GrDrawState& drawState = this->getDrawState();
michael@0 1256 const GrRenderTarget* rt = drawState.getRenderTarget();
michael@0 1257 // parent class should never let us get here with no RT
michael@0 1258 SkASSERT(NULL != rt);
michael@0 1259
michael@0 1260 if (canIgnoreRect && this->glCaps().fullClearIsFree()) {
michael@0 1261 rect = NULL;
michael@0 1262 }
michael@0 1263
michael@0 1264 SkIRect clippedRect;
michael@0 1265 if (NULL != rect) {
michael@0 1266 // flushScissor expects rect to be clipped to the target.
michael@0 1267 clippedRect = *rect;
michael@0 1268 SkIRect rtRect = SkIRect::MakeWH(rt->width(), rt->height());
michael@0 1269 if (clippedRect.intersect(rtRect)) {
michael@0 1270 rect = &clippedRect;
michael@0 1271 } else {
michael@0 1272 return;
michael@0 1273 }
michael@0 1274 }
michael@0 1275
michael@0 1276 this->flushRenderTarget(rect);
michael@0 1277 GrAutoTRestore<ScissorState> asr(&fScissorState);
michael@0 1278 fScissorState.fEnabled = (NULL != rect);
michael@0 1279 if (fScissorState.fEnabled) {
michael@0 1280 fScissorState.fRect = *rect;
michael@0 1281 }
michael@0 1282 this->flushScissor();
michael@0 1283
michael@0 1284 GrGLfloat r, g, b, a;
michael@0 1285 static const GrGLfloat scale255 = 1.f / 255.f;
michael@0 1286 a = GrColorUnpackA(color) * scale255;
michael@0 1287 GrGLfloat scaleRGB = scale255;
michael@0 1288 r = GrColorUnpackR(color) * scaleRGB;
michael@0 1289 g = GrColorUnpackG(color) * scaleRGB;
michael@0 1290 b = GrColorUnpackB(color) * scaleRGB;
michael@0 1291
michael@0 1292 GL_CALL(ColorMask(GR_GL_TRUE, GR_GL_TRUE, GR_GL_TRUE, GR_GL_TRUE));
michael@0 1293 fHWWriteToColor = kYes_TriState;
michael@0 1294 GL_CALL(ClearColor(r, g, b, a));
michael@0 1295 GL_CALL(Clear(GR_GL_COLOR_BUFFER_BIT));
michael@0 1296 }
michael@0 1297
michael@0 1298 void GrGpuGL::clearStencil() {
michael@0 1299 if (NULL == this->getDrawState().getRenderTarget()) {
michael@0 1300 return;
michael@0 1301 }
michael@0 1302
michael@0 1303 this->flushRenderTarget(&SkIRect::EmptyIRect());
michael@0 1304
michael@0 1305 GrAutoTRestore<ScissorState> asr(&fScissorState);
michael@0 1306 fScissorState.fEnabled = false;
michael@0 1307 this->flushScissor();
michael@0 1308
michael@0 1309 GL_CALL(StencilMask(0xffffffff));
michael@0 1310 GL_CALL(ClearStencil(0));
michael@0 1311 GL_CALL(Clear(GR_GL_STENCIL_BUFFER_BIT));
michael@0 1312 fHWStencilSettings.invalidate();
michael@0 1313 }
michael@0 1314
michael@0 1315 void GrGpuGL::clearStencilClip(const SkIRect& rect, bool insideClip) {
michael@0 1316 const GrDrawState& drawState = this->getDrawState();
michael@0 1317 const GrRenderTarget* rt = drawState.getRenderTarget();
michael@0 1318 SkASSERT(NULL != rt);
michael@0 1319
michael@0 1320 // this should only be called internally when we know we have a
michael@0 1321 // stencil buffer.
michael@0 1322 SkASSERT(NULL != rt->getStencilBuffer());
michael@0 1323 GrGLint stencilBitCount = rt->getStencilBuffer()->bits();
michael@0 1324 #if 0
michael@0 1325 SkASSERT(stencilBitCount > 0);
michael@0 1326 GrGLint clipStencilMask = (1 << (stencilBitCount - 1));
michael@0 1327 #else
michael@0 1328 // we could just clear the clip bit but when we go through
michael@0 1329 // ANGLE a partial stencil mask will cause clears to be
michael@0 1330 // turned into draws. Our contract on GrDrawTarget says that
michael@0 1331 // changing the clip between stencil passes may or may not
michael@0 1332 // zero the client's clip bits. So we just clear the whole thing.
michael@0 1333 static const GrGLint clipStencilMask = ~0;
michael@0 1334 #endif
michael@0 1335 GrGLint value;
michael@0 1336 if (insideClip) {
michael@0 1337 value = (1 << (stencilBitCount - 1));
michael@0 1338 } else {
michael@0 1339 value = 0;
michael@0 1340 }
michael@0 1341 this->flushRenderTarget(&SkIRect::EmptyIRect());
michael@0 1342
michael@0 1343 GrAutoTRestore<ScissorState> asr(&fScissorState);
michael@0 1344 fScissorState.fEnabled = true;
michael@0 1345 fScissorState.fRect = rect;
michael@0 1346 this->flushScissor();
michael@0 1347
michael@0 1348 GL_CALL(StencilMask((uint32_t) clipStencilMask));
michael@0 1349 GL_CALL(ClearStencil(value));
michael@0 1350 GL_CALL(Clear(GR_GL_STENCIL_BUFFER_BIT));
michael@0 1351 fHWStencilSettings.invalidate();
michael@0 1352 }
michael@0 1353
michael@0 1354 void GrGpuGL::onForceRenderTargetFlush() {
michael@0 1355 this->flushRenderTarget(&SkIRect::EmptyIRect());
michael@0 1356 }
michael@0 1357
michael@0 1358 bool GrGpuGL::readPixelsWillPayForYFlip(GrRenderTarget* renderTarget,
michael@0 1359 int left, int top,
michael@0 1360 int width, int height,
michael@0 1361 GrPixelConfig config,
michael@0 1362 size_t rowBytes) const {
michael@0 1363 // If this rendertarget is aready TopLeft, we don't need to flip.
michael@0 1364 if (kTopLeft_GrSurfaceOrigin == renderTarget->origin()) {
michael@0 1365 return false;
michael@0 1366 }
michael@0 1367
michael@0 1368 // if GL can do the flip then we'll never pay for it.
michael@0 1369 if (this->glCaps().packFlipYSupport()) {
michael@0 1370 return false;
michael@0 1371 }
michael@0 1372
michael@0 1373 // If we have to do memcpy to handle non-trim rowBytes then we
michael@0 1374 // get the flip for free. Otherwise it costs.
michael@0 1375 if (this->glCaps().packRowLengthSupport()) {
michael@0 1376 return true;
michael@0 1377 }
michael@0 1378 // If we have to do memcpys to handle rowBytes then y-flip is free
michael@0 1379 // Note the rowBytes might be tight to the passed in data, but if data
michael@0 1380 // gets clipped in x to the target the rowBytes will no longer be tight.
michael@0 1381 if (left >= 0 && (left + width) < renderTarget->width()) {
michael@0 1382 return 0 == rowBytes ||
michael@0 1383 GrBytesPerPixel(config) * width == rowBytes;
michael@0 1384 } else {
michael@0 1385 return false;
michael@0 1386 }
michael@0 1387 }
michael@0 1388
michael@0 1389 bool GrGpuGL::onReadPixels(GrRenderTarget* target,
michael@0 1390 int left, int top,
michael@0 1391 int width, int height,
michael@0 1392 GrPixelConfig config,
michael@0 1393 void* buffer,
michael@0 1394 size_t rowBytes) {
michael@0 1395 GrGLenum format;
michael@0 1396 GrGLenum type;
michael@0 1397 bool flipY = kBottomLeft_GrSurfaceOrigin == target->origin();
michael@0 1398 if (!this->configToGLFormats(config, false, NULL, &format, &type)) {
michael@0 1399 return false;
michael@0 1400 }
michael@0 1401 size_t bpp = GrBytesPerPixel(config);
michael@0 1402 if (!adjust_pixel_ops_params(target->width(), target->height(), bpp,
michael@0 1403 &left, &top, &width, &height,
michael@0 1404 const_cast<const void**>(&buffer),
michael@0 1405 &rowBytes)) {
michael@0 1406 return false;
michael@0 1407 }
michael@0 1408
michael@0 1409 // resolve the render target if necessary
michael@0 1410 GrGLRenderTarget* tgt = static_cast<GrGLRenderTarget*>(target);
michael@0 1411 GrDrawState::AutoRenderTargetRestore artr;
michael@0 1412 switch (tgt->getResolveType()) {
michael@0 1413 case GrGLRenderTarget::kCantResolve_ResolveType:
michael@0 1414 return false;
michael@0 1415 case GrGLRenderTarget::kAutoResolves_ResolveType:
michael@0 1416 artr.set(this->drawState(), target);
michael@0 1417 this->flushRenderTarget(&SkIRect::EmptyIRect());
michael@0 1418 break;
michael@0 1419 case GrGLRenderTarget::kCanResolve_ResolveType:
michael@0 1420 this->onResolveRenderTarget(tgt);
michael@0 1421 // we don't track the state of the READ FBO ID.
michael@0 1422 GL_CALL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER,
michael@0 1423 tgt->textureFBOID()));
michael@0 1424 break;
michael@0 1425 default:
michael@0 1426 GrCrash("Unknown resolve type");
michael@0 1427 }
michael@0 1428
michael@0 1429 const GrGLIRect& glvp = tgt->getViewport();
michael@0 1430
michael@0 1431 // the read rect is viewport-relative
michael@0 1432 GrGLIRect readRect;
michael@0 1433 readRect.setRelativeTo(glvp, left, top, width, height, target->origin());
michael@0 1434
michael@0 1435 size_t tightRowBytes = bpp * width;
michael@0 1436 if (0 == rowBytes) {
michael@0 1437 rowBytes = tightRowBytes;
michael@0 1438 }
michael@0 1439 size_t readDstRowBytes = tightRowBytes;
michael@0 1440 void* readDst = buffer;
michael@0 1441
michael@0 1442 // determine if GL can read using the passed rowBytes or if we need
michael@0 1443 // a scratch buffer.
michael@0 1444 SkAutoSMalloc<32 * sizeof(GrColor)> scratch;
michael@0 1445 if (rowBytes != tightRowBytes) {
michael@0 1446 if (this->glCaps().packRowLengthSupport()) {
michael@0 1447 SkASSERT(!(rowBytes % sizeof(GrColor)));
michael@0 1448 GL_CALL(PixelStorei(GR_GL_PACK_ROW_LENGTH,
michael@0 1449 static_cast<GrGLint>(rowBytes / sizeof(GrColor))));
michael@0 1450 readDstRowBytes = rowBytes;
michael@0 1451 } else {
michael@0 1452 scratch.reset(tightRowBytes * height);
michael@0 1453 readDst = scratch.get();
michael@0 1454 }
michael@0 1455 }
michael@0 1456 if (flipY && this->glCaps().packFlipYSupport()) {
michael@0 1457 GL_CALL(PixelStorei(GR_GL_PACK_REVERSE_ROW_ORDER, 1));
michael@0 1458 }
michael@0 1459 GL_CALL(ReadPixels(readRect.fLeft, readRect.fBottom,
michael@0 1460 readRect.fWidth, readRect.fHeight,
michael@0 1461 format, type, readDst));
michael@0 1462 if (readDstRowBytes != tightRowBytes) {
michael@0 1463 SkASSERT(this->glCaps().packRowLengthSupport());
michael@0 1464 GL_CALL(PixelStorei(GR_GL_PACK_ROW_LENGTH, 0));
michael@0 1465 }
michael@0 1466 if (flipY && this->glCaps().packFlipYSupport()) {
michael@0 1467 GL_CALL(PixelStorei(GR_GL_PACK_REVERSE_ROW_ORDER, 0));
michael@0 1468 flipY = false;
michael@0 1469 }
michael@0 1470
michael@0 1471 // now reverse the order of the rows, since GL's are bottom-to-top, but our
michael@0 1472 // API presents top-to-bottom. We must preserve the padding contents. Note
michael@0 1473 // that the above readPixels did not overwrite the padding.
michael@0 1474 if (readDst == buffer) {
michael@0 1475 SkASSERT(rowBytes == readDstRowBytes);
michael@0 1476 if (flipY) {
michael@0 1477 scratch.reset(tightRowBytes);
michael@0 1478 void* tmpRow = scratch.get();
michael@0 1479 // flip y in-place by rows
michael@0 1480 const int halfY = height >> 1;
michael@0 1481 char* top = reinterpret_cast<char*>(buffer);
michael@0 1482 char* bottom = top + (height - 1) * rowBytes;
michael@0 1483 for (int y = 0; y < halfY; y++) {
michael@0 1484 memcpy(tmpRow, top, tightRowBytes);
michael@0 1485 memcpy(top, bottom, tightRowBytes);
michael@0 1486 memcpy(bottom, tmpRow, tightRowBytes);
michael@0 1487 top += rowBytes;
michael@0 1488 bottom -= rowBytes;
michael@0 1489 }
michael@0 1490 }
michael@0 1491 } else {
michael@0 1492 SkASSERT(readDst != buffer); SkASSERT(rowBytes != tightRowBytes);
michael@0 1493 // copy from readDst to buffer while flipping y
michael@0 1494 // const int halfY = height >> 1;
michael@0 1495 const char* src = reinterpret_cast<const char*>(readDst);
michael@0 1496 char* dst = reinterpret_cast<char*>(buffer);
michael@0 1497 if (flipY) {
michael@0 1498 dst += (height-1) * rowBytes;
michael@0 1499 }
michael@0 1500 for (int y = 0; y < height; y++) {
michael@0 1501 memcpy(dst, src, tightRowBytes);
michael@0 1502 src += readDstRowBytes;
michael@0 1503 if (!flipY) {
michael@0 1504 dst += rowBytes;
michael@0 1505 } else {
michael@0 1506 dst -= rowBytes;
michael@0 1507 }
michael@0 1508 }
michael@0 1509 }
michael@0 1510 return true;
michael@0 1511 }
michael@0 1512
michael@0 1513 void GrGpuGL::flushRenderTarget(const SkIRect* bound) {
michael@0 1514
michael@0 1515 GrGLRenderTarget* rt =
michael@0 1516 static_cast<GrGLRenderTarget*>(this->drawState()->getRenderTarget());
michael@0 1517 SkASSERT(NULL != rt);
michael@0 1518
michael@0 1519 if (fHWBoundRenderTarget != rt) {
michael@0 1520 GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, rt->renderFBOID()));
michael@0 1521 #ifdef SK_DEBUG
michael@0 1522 // don't do this check in Chromium -- this is causing
michael@0 1523 // lots of repeated command buffer flushes when the compositor is
michael@0 1524 // rendering with Ganesh, which is really slow; even too slow for
michael@0 1525 // Debug mode.
michael@0 1526 if (!this->glContext().isChromium()) {
michael@0 1527 GrGLenum status;
michael@0 1528 GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
michael@0 1529 if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
michael@0 1530 GrPrintf("GrGpuGL::flushRenderTarget glCheckFramebufferStatus %x\n", status);
michael@0 1531 }
michael@0 1532 }
michael@0 1533 #endif
michael@0 1534 fHWBoundRenderTarget = rt;
michael@0 1535 const GrGLIRect& vp = rt->getViewport();
michael@0 1536 if (fHWViewport != vp) {
michael@0 1537 vp.pushToGLViewport(this->glInterface());
michael@0 1538 fHWViewport = vp;
michael@0 1539 }
michael@0 1540 }
michael@0 1541 if (NULL == bound || !bound->isEmpty()) {
michael@0 1542 rt->flagAsNeedingResolve(bound);
michael@0 1543 }
michael@0 1544
michael@0 1545 GrTexture *texture = rt->asTexture();
michael@0 1546 if (texture) {
michael@0 1547 texture->dirtyMipMaps(true);
michael@0 1548 }
michael@0 1549 }
michael@0 1550
michael@0 1551 GrGLenum gPrimitiveType2GLMode[] = {
michael@0 1552 GR_GL_TRIANGLES,
michael@0 1553 GR_GL_TRIANGLE_STRIP,
michael@0 1554 GR_GL_TRIANGLE_FAN,
michael@0 1555 GR_GL_POINTS,
michael@0 1556 GR_GL_LINES,
michael@0 1557 GR_GL_LINE_STRIP
michael@0 1558 };
michael@0 1559
michael@0 1560 #define SWAP_PER_DRAW 0
michael@0 1561
michael@0 1562 #if SWAP_PER_DRAW
michael@0 1563 #if defined(SK_BUILD_FOR_MAC)
michael@0 1564 #include <AGL/agl.h>
michael@0 1565 #elif defined(SK_BUILD_FOR_WIN32)
michael@0 1566 #include <gl/GL.h>
michael@0 1567 void SwapBuf() {
michael@0 1568 DWORD procID = GetCurrentProcessId();
michael@0 1569 HWND hwnd = GetTopWindow(GetDesktopWindow());
michael@0 1570 while(hwnd) {
michael@0 1571 DWORD wndProcID = 0;
michael@0 1572 GetWindowThreadProcessId(hwnd, &wndProcID);
michael@0 1573 if(wndProcID == procID) {
michael@0 1574 SwapBuffers(GetDC(hwnd));
michael@0 1575 }
michael@0 1576 hwnd = GetNextWindow(hwnd, GW_HWNDNEXT);
michael@0 1577 }
michael@0 1578 }
michael@0 1579 #endif
michael@0 1580 #endif
michael@0 1581
michael@0 1582 void GrGpuGL::onGpuDraw(const DrawInfo& info) {
michael@0 1583 size_t indexOffsetInBytes;
michael@0 1584 this->setupGeometry(info, &indexOffsetInBytes);
michael@0 1585
michael@0 1586 SkASSERT((size_t)info.primitiveType() < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
michael@0 1587
michael@0 1588 if (info.isIndexed()) {
michael@0 1589 GrGLvoid* indices =
michael@0 1590 reinterpret_cast<GrGLvoid*>(indexOffsetInBytes + sizeof(uint16_t) * info.startIndex());
michael@0 1591 // info.startVertex() was accounted for by setupGeometry.
michael@0 1592 GL_CALL(DrawElements(gPrimitiveType2GLMode[info.primitiveType()],
michael@0 1593 info.indexCount(),
michael@0 1594 GR_GL_UNSIGNED_SHORT,
michael@0 1595 indices));
michael@0 1596 } else {
michael@0 1597 // Pass 0 for parameter first. We have to adjust glVertexAttribPointer() to account for
michael@0 1598 // startVertex in the DrawElements case. So we always rely on setupGeometry to have
michael@0 1599 // accounted for startVertex.
michael@0 1600 GL_CALL(DrawArrays(gPrimitiveType2GLMode[info.primitiveType()], 0, info.vertexCount()));
michael@0 1601 }
michael@0 1602 #if SWAP_PER_DRAW
michael@0 1603 glFlush();
michael@0 1604 #if defined(SK_BUILD_FOR_MAC)
michael@0 1605 aglSwapBuffers(aglGetCurrentContext());
michael@0 1606 int set_a_break_pt_here = 9;
michael@0 1607 aglSwapBuffers(aglGetCurrentContext());
michael@0 1608 #elif defined(SK_BUILD_FOR_WIN32)
michael@0 1609 SwapBuf();
michael@0 1610 int set_a_break_pt_here = 9;
michael@0 1611 SwapBuf();
michael@0 1612 #endif
michael@0 1613 #endif
michael@0 1614 }
michael@0 1615
michael@0 1616 static GrGLenum gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op) {
michael@0 1617 switch (op) {
michael@0 1618 default:
michael@0 1619 GrCrash("Unexpected path fill.");
michael@0 1620 /* fallthrough */;
michael@0 1621 case kIncClamp_StencilOp:
michael@0 1622 return GR_GL_COUNT_UP;
michael@0 1623 case kInvert_StencilOp:
michael@0 1624 return GR_GL_INVERT;
michael@0 1625 }
michael@0 1626 }
michael@0 1627
michael@0 1628 void GrGpuGL::onGpuStencilPath(const GrPath* path, SkPath::FillType fill) {
michael@0 1629 SkASSERT(this->caps()->pathRenderingSupport());
michael@0 1630
michael@0 1631 GrGLuint id = static_cast<const GrGLPath*>(path)->pathID();
michael@0 1632 SkASSERT(NULL != this->drawState()->getRenderTarget());
michael@0 1633 SkASSERT(NULL != this->drawState()->getRenderTarget()->getStencilBuffer());
michael@0 1634
michael@0 1635 flushPathStencilSettings(fill);
michael@0 1636
michael@0 1637 // Decide how to manipulate the stencil buffer based on the fill rule.
michael@0 1638 SkASSERT(!fHWPathStencilSettings.isTwoSided());
michael@0 1639
michael@0 1640 GrGLenum fillMode =
michael@0 1641 gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
michael@0 1642 GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
michael@0 1643 GL_CALL(StencilFillPath(id, fillMode, writeMask));
michael@0 1644 }
michael@0 1645
michael@0 1646 void GrGpuGL::onGpuDrawPath(const GrPath* path, SkPath::FillType fill) {
michael@0 1647 SkASSERT(this->caps()->pathRenderingSupport());
michael@0 1648
michael@0 1649 GrGLuint id = static_cast<const GrGLPath*>(path)->pathID();
michael@0 1650 SkASSERT(NULL != this->drawState()->getRenderTarget());
michael@0 1651 SkASSERT(NULL != this->drawState()->getRenderTarget()->getStencilBuffer());
michael@0 1652 SkASSERT(!fCurrentProgram->hasVertexShader());
michael@0 1653
michael@0 1654 flushPathStencilSettings(fill);
michael@0 1655 const SkStrokeRec& stroke = path->getStroke();
michael@0 1656
michael@0 1657 SkPath::FillType nonInvertedFill = SkPath::ConvertToNonInverseFillType(fill);
michael@0 1658 SkASSERT(!fHWPathStencilSettings.isTwoSided());
michael@0 1659 GrGLenum fillMode =
michael@0 1660 gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
michael@0 1661 GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
michael@0 1662
michael@0 1663 if (stroke.isFillStyle() || SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
michael@0 1664 GL_CALL(StencilFillPath(id, fillMode, writeMask));
michael@0 1665 }
michael@0 1666 if (stroke.needToApply()) {
michael@0 1667 GL_CALL(StencilStrokePath(id, 0xffff, writeMask));
michael@0 1668 }
michael@0 1669
michael@0 1670 if (nonInvertedFill == fill) {
michael@0 1671 if (stroke.needToApply()) {
michael@0 1672 GL_CALL(CoverStrokePath(id, GR_GL_BOUNDING_BOX));
michael@0 1673 } else {
michael@0 1674 GL_CALL(CoverFillPath(id, GR_GL_BOUNDING_BOX));
michael@0 1675 }
michael@0 1676 } else {
michael@0 1677 GrDrawState* drawState = this->drawState();
michael@0 1678 GrDrawState::AutoViewMatrixRestore avmr;
michael@0 1679 SkRect bounds = SkRect::MakeLTRB(0, 0,
michael@0 1680 SkIntToScalar(drawState->getRenderTarget()->width()),
michael@0 1681 SkIntToScalar(drawState->getRenderTarget()->height()));
michael@0 1682 SkMatrix vmi;
michael@0 1683 // mapRect through persp matrix may not be correct
michael@0 1684 if (!drawState->getViewMatrix().hasPerspective() && drawState->getViewInverse(&vmi)) {
michael@0 1685 vmi.mapRect(&bounds);
michael@0 1686 // theoretically could set bloat = 0, instead leave it because of matrix inversion
michael@0 1687 // precision.
michael@0 1688 SkScalar bloat = drawState->getViewMatrix().getMaxStretch() * SK_ScalarHalf;
michael@0 1689 bounds.outset(bloat, bloat);
michael@0 1690 } else {
michael@0 1691 avmr.setIdentity(drawState);
michael@0 1692 }
michael@0 1693
michael@0 1694 this->drawSimpleRect(bounds, NULL);
michael@0 1695 }
michael@0 1696 }
michael@0 1697
michael@0 1698 void GrGpuGL::onResolveRenderTarget(GrRenderTarget* target) {
michael@0 1699 GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(target);
michael@0 1700 if (rt->needsResolve()) {
michael@0 1701 // Some extensions automatically resolves the texture when it is read.
michael@0 1702 if (this->glCaps().usesMSAARenderBuffers()) {
michael@0 1703 SkASSERT(rt->textureFBOID() != rt->renderFBOID());
michael@0 1704 GL_CALL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER, rt->renderFBOID()));
michael@0 1705 GL_CALL(BindFramebuffer(GR_GL_DRAW_FRAMEBUFFER, rt->textureFBOID()));
michael@0 1706 // make sure we go through flushRenderTarget() since we've modified
michael@0 1707 // the bound DRAW FBO ID.
michael@0 1708 fHWBoundRenderTarget = NULL;
michael@0 1709 const GrGLIRect& vp = rt->getViewport();
michael@0 1710 const SkIRect dirtyRect = rt->getResolveRect();
michael@0 1711 GrGLIRect r;
michael@0 1712 r.setRelativeTo(vp, dirtyRect.fLeft, dirtyRect.fTop,
michael@0 1713 dirtyRect.width(), dirtyRect.height(), target->origin());
michael@0 1714
michael@0 1715 GrAutoTRestore<ScissorState> asr;
michael@0 1716 if (GrGLCaps::kES_Apple_MSFBOType == this->glCaps().msFBOType()) {
michael@0 1717 // Apple's extension uses the scissor as the blit bounds.
michael@0 1718 asr.reset(&fScissorState);
michael@0 1719 fScissorState.fEnabled = true;
michael@0 1720 fScissorState.fRect = dirtyRect;
michael@0 1721 this->flushScissor();
michael@0 1722 GL_CALL(ResolveMultisampleFramebuffer());
michael@0 1723 } else {
michael@0 1724 if (GrGLCaps::kDesktop_EXT_MSFBOType == this->glCaps().msFBOType()) {
michael@0 1725 // this respects the scissor during the blit, so disable it.
michael@0 1726 asr.reset(&fScissorState);
michael@0 1727 fScissorState.fEnabled = false;
michael@0 1728 this->flushScissor();
michael@0 1729 }
michael@0 1730 int right = r.fLeft + r.fWidth;
michael@0 1731 int top = r.fBottom + r.fHeight;
michael@0 1732 GL_CALL(BlitFramebuffer(r.fLeft, r.fBottom, right, top,
michael@0 1733 r.fLeft, r.fBottom, right, top,
michael@0 1734 GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST));
michael@0 1735 }
michael@0 1736 }
michael@0 1737 rt->flagAsResolved();
michael@0 1738 }
michael@0 1739 }
michael@0 1740
michael@0 1741 namespace {
michael@0 1742
michael@0 1743 GrGLenum gr_to_gl_stencil_func(GrStencilFunc basicFunc) {
michael@0 1744 static const GrGLenum gTable[] = {
michael@0 1745 GR_GL_ALWAYS, // kAlways_StencilFunc
michael@0 1746 GR_GL_NEVER, // kNever_StencilFunc
michael@0 1747 GR_GL_GREATER, // kGreater_StencilFunc
michael@0 1748 GR_GL_GEQUAL, // kGEqual_StencilFunc
michael@0 1749 GR_GL_LESS, // kLess_StencilFunc
michael@0 1750 GR_GL_LEQUAL, // kLEqual_StencilFunc,
michael@0 1751 GR_GL_EQUAL, // kEqual_StencilFunc,
michael@0 1752 GR_GL_NOTEQUAL, // kNotEqual_StencilFunc,
michael@0 1753 };
michael@0 1754 GR_STATIC_ASSERT(GR_ARRAY_COUNT(gTable) == kBasicStencilFuncCount);
michael@0 1755 GR_STATIC_ASSERT(0 == kAlways_StencilFunc);
michael@0 1756 GR_STATIC_ASSERT(1 == kNever_StencilFunc);
michael@0 1757 GR_STATIC_ASSERT(2 == kGreater_StencilFunc);
michael@0 1758 GR_STATIC_ASSERT(3 == kGEqual_StencilFunc);
michael@0 1759 GR_STATIC_ASSERT(4 == kLess_StencilFunc);
michael@0 1760 GR_STATIC_ASSERT(5 == kLEqual_StencilFunc);
michael@0 1761 GR_STATIC_ASSERT(6 == kEqual_StencilFunc);
michael@0 1762 GR_STATIC_ASSERT(7 == kNotEqual_StencilFunc);
michael@0 1763 SkASSERT((unsigned) basicFunc < kBasicStencilFuncCount);
michael@0 1764
michael@0 1765 return gTable[basicFunc];
michael@0 1766 }
michael@0 1767
michael@0 1768 GrGLenum gr_to_gl_stencil_op(GrStencilOp op) {
michael@0 1769 static const GrGLenum gTable[] = {
michael@0 1770 GR_GL_KEEP, // kKeep_StencilOp
michael@0 1771 GR_GL_REPLACE, // kReplace_StencilOp
michael@0 1772 GR_GL_INCR_WRAP, // kIncWrap_StencilOp
michael@0 1773 GR_GL_INCR, // kIncClamp_StencilOp
michael@0 1774 GR_GL_DECR_WRAP, // kDecWrap_StencilOp
michael@0 1775 GR_GL_DECR, // kDecClamp_StencilOp
michael@0 1776 GR_GL_ZERO, // kZero_StencilOp
michael@0 1777 GR_GL_INVERT, // kInvert_StencilOp
michael@0 1778 };
michael@0 1779 GR_STATIC_ASSERT(GR_ARRAY_COUNT(gTable) == kStencilOpCount);
michael@0 1780 GR_STATIC_ASSERT(0 == kKeep_StencilOp);
michael@0 1781 GR_STATIC_ASSERT(1 == kReplace_StencilOp);
michael@0 1782 GR_STATIC_ASSERT(2 == kIncWrap_StencilOp);
michael@0 1783 GR_STATIC_ASSERT(3 == kIncClamp_StencilOp);
michael@0 1784 GR_STATIC_ASSERT(4 == kDecWrap_StencilOp);
michael@0 1785 GR_STATIC_ASSERT(5 == kDecClamp_StencilOp);
michael@0 1786 GR_STATIC_ASSERT(6 == kZero_StencilOp);
michael@0 1787 GR_STATIC_ASSERT(7 == kInvert_StencilOp);
michael@0 1788 SkASSERT((unsigned) op < kStencilOpCount);
michael@0 1789 return gTable[op];
michael@0 1790 }
michael@0 1791
michael@0 1792 void set_gl_stencil(const GrGLInterface* gl,
michael@0 1793 const GrStencilSettings& settings,
michael@0 1794 GrGLenum glFace,
michael@0 1795 GrStencilSettings::Face grFace) {
michael@0 1796 GrGLenum glFunc = gr_to_gl_stencil_func(settings.func(grFace));
michael@0 1797 GrGLenum glFailOp = gr_to_gl_stencil_op(settings.failOp(grFace));
michael@0 1798 GrGLenum glPassOp = gr_to_gl_stencil_op(settings.passOp(grFace));
michael@0 1799
michael@0 1800 GrGLint ref = settings.funcRef(grFace);
michael@0 1801 GrGLint mask = settings.funcMask(grFace);
michael@0 1802 GrGLint writeMask = settings.writeMask(grFace);
michael@0 1803
michael@0 1804 if (GR_GL_FRONT_AND_BACK == glFace) {
michael@0 1805 // we call the combined func just in case separate stencil is not
michael@0 1806 // supported.
michael@0 1807 GR_GL_CALL(gl, StencilFunc(glFunc, ref, mask));
michael@0 1808 GR_GL_CALL(gl, StencilMask(writeMask));
michael@0 1809 GR_GL_CALL(gl, StencilOp(glFailOp, glPassOp, glPassOp));
michael@0 1810 } else {
michael@0 1811 GR_GL_CALL(gl, StencilFuncSeparate(glFace, glFunc, ref, mask));
michael@0 1812 GR_GL_CALL(gl, StencilMaskSeparate(glFace, writeMask));
michael@0 1813 GR_GL_CALL(gl, StencilOpSeparate(glFace, glFailOp, glPassOp, glPassOp));
michael@0 1814 }
michael@0 1815 }
michael@0 1816 }
michael@0 1817
michael@0 1818 void GrGpuGL::flushStencil(DrawType type) {
michael@0 1819 if (kStencilPath_DrawType != type && fHWStencilSettings != fStencilSettings) {
michael@0 1820 if (fStencilSettings.isDisabled()) {
michael@0 1821 if (kNo_TriState != fHWStencilTestEnabled) {
michael@0 1822 GL_CALL(Disable(GR_GL_STENCIL_TEST));
michael@0 1823 fHWStencilTestEnabled = kNo_TriState;
michael@0 1824 }
michael@0 1825 } else {
michael@0 1826 if (kYes_TriState != fHWStencilTestEnabled) {
michael@0 1827 GL_CALL(Enable(GR_GL_STENCIL_TEST));
michael@0 1828 fHWStencilTestEnabled = kYes_TriState;
michael@0 1829 }
michael@0 1830 }
michael@0 1831 if (!fStencilSettings.isDisabled()) {
michael@0 1832 if (this->caps()->twoSidedStencilSupport()) {
michael@0 1833 set_gl_stencil(this->glInterface(),
michael@0 1834 fStencilSettings,
michael@0 1835 GR_GL_FRONT,
michael@0 1836 GrStencilSettings::kFront_Face);
michael@0 1837 set_gl_stencil(this->glInterface(),
michael@0 1838 fStencilSettings,
michael@0 1839 GR_GL_BACK,
michael@0 1840 GrStencilSettings::kBack_Face);
michael@0 1841 } else {
michael@0 1842 set_gl_stencil(this->glInterface(),
michael@0 1843 fStencilSettings,
michael@0 1844 GR_GL_FRONT_AND_BACK,
michael@0 1845 GrStencilSettings::kFront_Face);
michael@0 1846 }
michael@0 1847 }
michael@0 1848 fHWStencilSettings = fStencilSettings;
michael@0 1849 }
michael@0 1850 }
michael@0 1851
michael@0 1852 void GrGpuGL::flushAAState(DrawType type) {
michael@0 1853 // At least some ATI linux drivers will render GL_LINES incorrectly when MSAA state is enabled but
michael@0 1854 // the target is not multisampled. Single pixel wide lines are rendered thicker than 1 pixel wide.
michael@0 1855 #if 0
michael@0 1856 // Replace RT_HAS_MSAA with this definition once this driver bug is no longer a relevant concern
michael@0 1857 #define RT_HAS_MSAA rt->isMultisampled()
michael@0 1858 #else
michael@0 1859 #define RT_HAS_MSAA (rt->isMultisampled() || kDrawLines_DrawType == type)
michael@0 1860 #endif
michael@0 1861
michael@0 1862 const GrRenderTarget* rt = this->getDrawState().getRenderTarget();
michael@0 1863 if (kGL_GrGLStandard == this->glStandard()) {
michael@0 1864 // ES doesn't support toggling GL_MULTISAMPLE and doesn't have
michael@0 1865 // smooth lines.
michael@0 1866 // we prefer smooth lines over multisampled lines
michael@0 1867 bool smoothLines = false;
michael@0 1868
michael@0 1869 if (kDrawLines_DrawType == type) {
michael@0 1870 smoothLines = this->willUseHWAALines();
michael@0 1871 if (smoothLines) {
michael@0 1872 if (kYes_TriState != fHWAAState.fSmoothLineEnabled) {
michael@0 1873 GL_CALL(Enable(GR_GL_LINE_SMOOTH));
michael@0 1874 fHWAAState.fSmoothLineEnabled = kYes_TriState;
michael@0 1875 // must disable msaa to use line smoothing
michael@0 1876 if (RT_HAS_MSAA &&
michael@0 1877 kNo_TriState != fHWAAState.fMSAAEnabled) {
michael@0 1878 GL_CALL(Disable(GR_GL_MULTISAMPLE));
michael@0 1879 fHWAAState.fMSAAEnabled = kNo_TriState;
michael@0 1880 }
michael@0 1881 }
michael@0 1882 } else {
michael@0 1883 if (kNo_TriState != fHWAAState.fSmoothLineEnabled) {
michael@0 1884 GL_CALL(Disable(GR_GL_LINE_SMOOTH));
michael@0 1885 fHWAAState.fSmoothLineEnabled = kNo_TriState;
michael@0 1886 }
michael@0 1887 }
michael@0 1888 }
michael@0 1889 if (!smoothLines && RT_HAS_MSAA) {
michael@0 1890 // FIXME: GL_NV_pr doesn't seem to like MSAA disabled. The paths
michael@0 1891 // convex hulls of each segment appear to get filled.
michael@0 1892 bool enableMSAA = kStencilPath_DrawType == type ||
michael@0 1893 this->getDrawState().isHWAntialiasState();
michael@0 1894 if (enableMSAA) {
michael@0 1895 if (kYes_TriState != fHWAAState.fMSAAEnabled) {
michael@0 1896 GL_CALL(Enable(GR_GL_MULTISAMPLE));
michael@0 1897 fHWAAState.fMSAAEnabled = kYes_TriState;
michael@0 1898 }
michael@0 1899 } else {
michael@0 1900 if (kNo_TriState != fHWAAState.fMSAAEnabled) {
michael@0 1901 GL_CALL(Disable(GR_GL_MULTISAMPLE));
michael@0 1902 fHWAAState.fMSAAEnabled = kNo_TriState;
michael@0 1903 }
michael@0 1904 }
michael@0 1905 }
michael@0 1906 }
michael@0 1907 }
michael@0 1908
michael@0 1909 void GrGpuGL::flushPathStencilSettings(SkPath::FillType fill) {
michael@0 1910 GrStencilSettings pathStencilSettings;
michael@0 1911 this->getPathStencilSettingsForFillType(fill, &pathStencilSettings);
michael@0 1912 if (fHWPathStencilSettings != pathStencilSettings) {
michael@0 1913 // Just the func, ref, and mask is set here. The op and write mask are params to the call
michael@0 1914 // that draws the path to the SB (glStencilFillPath)
michael@0 1915 GrGLenum func =
michael@0 1916 gr_to_gl_stencil_func(pathStencilSettings.func(GrStencilSettings::kFront_Face));
michael@0 1917 GL_CALL(PathStencilFunc(func,
michael@0 1918 pathStencilSettings.funcRef(GrStencilSettings::kFront_Face),
michael@0 1919 pathStencilSettings.funcMask(GrStencilSettings::kFront_Face)));
michael@0 1920
michael@0 1921 fHWPathStencilSettings = pathStencilSettings;
michael@0 1922 }
michael@0 1923 }
michael@0 1924
michael@0 1925 void GrGpuGL::flushBlend(bool isLines,
michael@0 1926 GrBlendCoeff srcCoeff,
michael@0 1927 GrBlendCoeff dstCoeff) {
michael@0 1928 if (isLines && this->willUseHWAALines()) {
michael@0 1929 if (kYes_TriState != fHWBlendState.fEnabled) {
michael@0 1930 GL_CALL(Enable(GR_GL_BLEND));
michael@0 1931 fHWBlendState.fEnabled = kYes_TriState;
michael@0 1932 }
michael@0 1933 if (kSA_GrBlendCoeff != fHWBlendState.fSrcCoeff ||
michael@0 1934 kISA_GrBlendCoeff != fHWBlendState.fDstCoeff) {
michael@0 1935 GL_CALL(BlendFunc(gXfermodeCoeff2Blend[kSA_GrBlendCoeff],
michael@0 1936 gXfermodeCoeff2Blend[kISA_GrBlendCoeff]));
michael@0 1937 fHWBlendState.fSrcCoeff = kSA_GrBlendCoeff;
michael@0 1938 fHWBlendState.fDstCoeff = kISA_GrBlendCoeff;
michael@0 1939 }
michael@0 1940 } else {
michael@0 1941 // any optimization to disable blending should
michael@0 1942 // have already been applied and tweaked the coeffs
michael@0 1943 // to (1, 0).
michael@0 1944 bool blendOff = kOne_GrBlendCoeff == srcCoeff &&
michael@0 1945 kZero_GrBlendCoeff == dstCoeff;
michael@0 1946 if (blendOff) {
michael@0 1947 if (kNo_TriState != fHWBlendState.fEnabled) {
michael@0 1948 GL_CALL(Disable(GR_GL_BLEND));
michael@0 1949 fHWBlendState.fEnabled = kNo_TriState;
michael@0 1950 }
michael@0 1951 } else {
michael@0 1952 if (kYes_TriState != fHWBlendState.fEnabled) {
michael@0 1953 GL_CALL(Enable(GR_GL_BLEND));
michael@0 1954 fHWBlendState.fEnabled = kYes_TriState;
michael@0 1955 }
michael@0 1956 if (fHWBlendState.fSrcCoeff != srcCoeff ||
michael@0 1957 fHWBlendState.fDstCoeff != dstCoeff) {
michael@0 1958 GL_CALL(BlendFunc(gXfermodeCoeff2Blend[srcCoeff],
michael@0 1959 gXfermodeCoeff2Blend[dstCoeff]));
michael@0 1960 fHWBlendState.fSrcCoeff = srcCoeff;
michael@0 1961 fHWBlendState.fDstCoeff = dstCoeff;
michael@0 1962 }
michael@0 1963 GrColor blendConst = this->getDrawState().getBlendConstant();
michael@0 1964 if ((BlendCoeffReferencesConstant(srcCoeff) ||
michael@0 1965 BlendCoeffReferencesConstant(dstCoeff)) &&
michael@0 1966 (!fHWBlendState.fConstColorValid ||
michael@0 1967 fHWBlendState.fConstColor != blendConst)) {
michael@0 1968 GrGLfloat c[4];
michael@0 1969 GrColorToRGBAFloat(blendConst, c);
michael@0 1970 GL_CALL(BlendColor(c[0], c[1], c[2], c[3]));
michael@0 1971 fHWBlendState.fConstColor = blendConst;
michael@0 1972 fHWBlendState.fConstColorValid = true;
michael@0 1973 }
michael@0 1974 }
michael@0 1975 }
michael@0 1976 }
michael@0 1977
michael@0 1978 static inline GrGLenum tile_to_gl_wrap(SkShader::TileMode tm) {
michael@0 1979 static const GrGLenum gWrapModes[] = {
michael@0 1980 GR_GL_CLAMP_TO_EDGE,
michael@0 1981 GR_GL_REPEAT,
michael@0 1982 GR_GL_MIRRORED_REPEAT
michael@0 1983 };
michael@0 1984 GR_STATIC_ASSERT(SkShader::kTileModeCount == SK_ARRAY_COUNT(gWrapModes));
michael@0 1985 GR_STATIC_ASSERT(0 == SkShader::kClamp_TileMode);
michael@0 1986 GR_STATIC_ASSERT(1 == SkShader::kRepeat_TileMode);
michael@0 1987 GR_STATIC_ASSERT(2 == SkShader::kMirror_TileMode);
michael@0 1988 return gWrapModes[tm];
michael@0 1989 }
michael@0 1990
michael@0 1991 void GrGpuGL::bindTexture(int unitIdx, const GrTextureParams& params, GrGLTexture* texture) {
michael@0 1992 SkASSERT(NULL != texture);
michael@0 1993
michael@0 1994 // If we created a rt/tex and rendered to it without using a texture and now we're texturing
michael@0 1995 // from the rt it will still be the last bound texture, but it needs resolving. So keep this
michael@0 1996 // out of the "last != next" check.
michael@0 1997 GrGLRenderTarget* texRT = static_cast<GrGLRenderTarget*>(texture->asRenderTarget());
michael@0 1998 if (NULL != texRT) {
michael@0 1999 this->onResolveRenderTarget(texRT);
michael@0 2000 }
michael@0 2001
michael@0 2002 if (fHWBoundTextures[unitIdx] != texture) {
michael@0 2003 this->setTextureUnit(unitIdx);
michael@0 2004 GL_CALL(BindTexture(GR_GL_TEXTURE_2D, texture->textureID()));
michael@0 2005 fHWBoundTextures[unitIdx] = texture;
michael@0 2006 }
michael@0 2007
michael@0 2008 ResetTimestamp timestamp;
michael@0 2009 const GrGLTexture::TexParams& oldTexParams = texture->getCachedTexParams(&timestamp);
michael@0 2010 bool setAll = timestamp < this->getResetTimestamp();
michael@0 2011 GrGLTexture::TexParams newTexParams;
michael@0 2012
michael@0 2013 static GrGLenum glMinFilterModes[] = {
michael@0 2014 GR_GL_NEAREST,
michael@0 2015 GR_GL_LINEAR,
michael@0 2016 GR_GL_LINEAR_MIPMAP_LINEAR
michael@0 2017 };
michael@0 2018 static GrGLenum glMagFilterModes[] = {
michael@0 2019 GR_GL_NEAREST,
michael@0 2020 GR_GL_LINEAR,
michael@0 2021 GR_GL_LINEAR
michael@0 2022 };
michael@0 2023 GrTextureParams::FilterMode filterMode = params.filterMode();
michael@0 2024 if (!this->caps()->mipMapSupport() && GrTextureParams::kMipMap_FilterMode == filterMode) {
michael@0 2025 filterMode = GrTextureParams::kBilerp_FilterMode;
michael@0 2026 }
michael@0 2027 newTexParams.fMinFilter = glMinFilterModes[filterMode];
michael@0 2028 newTexParams.fMagFilter = glMagFilterModes[filterMode];
michael@0 2029
michael@0 2030 if (GrTextureParams::kMipMap_FilterMode == filterMode && texture->mipMapsAreDirty()) {
michael@0 2031 // GL_CALL(Hint(GR_GL_GENERATE_MIPMAP_HINT,GR_GL_NICEST));
michael@0 2032 GL_CALL(GenerateMipmap(GR_GL_TEXTURE_2D));
michael@0 2033 texture->dirtyMipMaps(false);
michael@0 2034 }
michael@0 2035
michael@0 2036 newTexParams.fWrapS = tile_to_gl_wrap(params.getTileModeX());
michael@0 2037 newTexParams.fWrapT = tile_to_gl_wrap(params.getTileModeY());
michael@0 2038 memcpy(newTexParams.fSwizzleRGBA,
michael@0 2039 GrGLShaderBuilder::GetTexParamSwizzle(texture->config(), this->glCaps()),
michael@0 2040 sizeof(newTexParams.fSwizzleRGBA));
michael@0 2041 if (setAll || newTexParams.fMagFilter != oldTexParams.fMagFilter) {
michael@0 2042 this->setTextureUnit(unitIdx);
michael@0 2043 GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
michael@0 2044 GR_GL_TEXTURE_MAG_FILTER,
michael@0 2045 newTexParams.fMagFilter));
michael@0 2046 }
michael@0 2047 if (setAll || newTexParams.fMinFilter != oldTexParams.fMinFilter) {
michael@0 2048 this->setTextureUnit(unitIdx);
michael@0 2049 GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
michael@0 2050 GR_GL_TEXTURE_MIN_FILTER,
michael@0 2051 newTexParams.fMinFilter));
michael@0 2052 }
michael@0 2053 if (setAll || newTexParams.fWrapS != oldTexParams.fWrapS) {
michael@0 2054 this->setTextureUnit(unitIdx);
michael@0 2055 GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
michael@0 2056 GR_GL_TEXTURE_WRAP_S,
michael@0 2057 newTexParams.fWrapS));
michael@0 2058 }
michael@0 2059 if (setAll || newTexParams.fWrapT != oldTexParams.fWrapT) {
michael@0 2060 this->setTextureUnit(unitIdx);
michael@0 2061 GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
michael@0 2062 GR_GL_TEXTURE_WRAP_T,
michael@0 2063 newTexParams.fWrapT));
michael@0 2064 }
michael@0 2065 if (this->glCaps().textureSwizzleSupport() &&
michael@0 2066 (setAll || memcmp(newTexParams.fSwizzleRGBA,
michael@0 2067 oldTexParams.fSwizzleRGBA,
michael@0 2068 sizeof(newTexParams.fSwizzleRGBA)))) {
michael@0 2069 this->setTextureUnit(unitIdx);
michael@0 2070 if (this->glStandard() == kGLES_GrGLStandard) {
michael@0 2071 // ES3 added swizzle support but not GL_TEXTURE_SWIZZLE_RGBA.
michael@0 2072 const GrGLenum* swizzle = newTexParams.fSwizzleRGBA;
michael@0 2073 GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_SWIZZLE_R, swizzle[0]));
michael@0 2074 GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_SWIZZLE_G, swizzle[1]));
michael@0 2075 GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_SWIZZLE_B, swizzle[2]));
michael@0 2076 GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_SWIZZLE_A, swizzle[3]));
michael@0 2077 } else {
michael@0 2078 GR_STATIC_ASSERT(sizeof(newTexParams.fSwizzleRGBA[0]) == sizeof(GrGLint));
michael@0 2079 const GrGLint* swizzle = reinterpret_cast<const GrGLint*>(newTexParams.fSwizzleRGBA);
michael@0 2080 GL_CALL(TexParameteriv(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_SWIZZLE_RGBA, swizzle));
michael@0 2081 }
michael@0 2082 }
michael@0 2083 texture->setCachedTexParams(newTexParams, this->getResetTimestamp());
michael@0 2084 }
michael@0 2085
michael@0 2086 void GrGpuGL::setProjectionMatrix(const SkMatrix& matrix,
michael@0 2087 const SkISize& renderTargetSize,
michael@0 2088 GrSurfaceOrigin renderTargetOrigin) {
michael@0 2089
michael@0 2090 SkASSERT(this->glCaps().fixedFunctionSupport());
michael@0 2091
michael@0 2092 if (renderTargetOrigin == fHWProjectionMatrixState.fRenderTargetOrigin &&
michael@0 2093 renderTargetSize == fHWProjectionMatrixState.fRenderTargetSize &&
michael@0 2094 matrix.cheapEqualTo(fHWProjectionMatrixState.fViewMatrix)) {
michael@0 2095 return;
michael@0 2096 }
michael@0 2097
michael@0 2098 fHWProjectionMatrixState.fViewMatrix = matrix;
michael@0 2099 fHWProjectionMatrixState.fRenderTargetSize = renderTargetSize;
michael@0 2100 fHWProjectionMatrixState.fRenderTargetOrigin = renderTargetOrigin;
michael@0 2101
michael@0 2102 GrGLfloat glMatrix[4 * 4];
michael@0 2103 fHWProjectionMatrixState.getGLMatrix<4>(glMatrix);
michael@0 2104 GL_CALL(MatrixMode(GR_GL_PROJECTION));
michael@0 2105 GL_CALL(LoadMatrixf(glMatrix));
michael@0 2106 }
michael@0 2107
michael@0 2108 void GrGpuGL::enableTexGen(int unitIdx,
michael@0 2109 TexGenComponents components,
michael@0 2110 const GrGLfloat* coefficients) {
michael@0 2111 SkASSERT(this->glCaps().fixedFunctionSupport());
michael@0 2112 SkASSERT(components >= kS_TexGenComponents && components <= kSTR_TexGenComponents);
michael@0 2113 SkASSERT(this->glCaps().maxFixedFunctionTextureCoords() >= unitIdx);
michael@0 2114
michael@0 2115 if (GR_GL_OBJECT_LINEAR == fHWTexGenSettings[unitIdx].fMode &&
michael@0 2116 components == fHWTexGenSettings[unitIdx].fNumComponents &&
michael@0 2117 !memcmp(coefficients, fHWTexGenSettings[unitIdx].fCoefficients,
michael@0 2118 3 * components * sizeof(GrGLfloat))) {
michael@0 2119 return;
michael@0 2120 }
michael@0 2121
michael@0 2122 this->setTextureUnit(unitIdx);
michael@0 2123
michael@0 2124 if (GR_GL_OBJECT_LINEAR != fHWTexGenSettings[unitIdx].fMode) {
michael@0 2125 for (int i = 0; i < 4; i++) {
michael@0 2126 GL_CALL(TexGeni(GR_GL_S + i, GR_GL_TEXTURE_GEN_MODE, GR_GL_OBJECT_LINEAR));
michael@0 2127 }
michael@0 2128 fHWTexGenSettings[unitIdx].fMode = GR_GL_OBJECT_LINEAR;
michael@0 2129 }
michael@0 2130
michael@0 2131 for (int i = fHWTexGenSettings[unitIdx].fNumComponents; i < components; i++) {
michael@0 2132 GL_CALL(Enable(GR_GL_TEXTURE_GEN_S + i));
michael@0 2133 }
michael@0 2134 for (int i = components; i < fHWTexGenSettings[unitIdx].fNumComponents; i++) {
michael@0 2135 GL_CALL(Disable(GR_GL_TEXTURE_GEN_S + i));
michael@0 2136 }
michael@0 2137 fHWTexGenSettings[unitIdx].fNumComponents = components;
michael@0 2138
michael@0 2139 for (int i = 0; i < components; i++) {
michael@0 2140 GrGLfloat plane[] = {coefficients[0 + 3 * i],
michael@0 2141 coefficients[1 + 3 * i],
michael@0 2142 0,
michael@0 2143 coefficients[2 + 3 * i]};
michael@0 2144 GL_CALL(TexGenfv(GR_GL_S + i, GR_GL_OBJECT_PLANE, plane));
michael@0 2145 }
michael@0 2146
michael@0 2147 if (this->caps()->pathRenderingSupport()) {
michael@0 2148 GL_CALL(PathTexGen(GR_GL_TEXTURE0 + unitIdx,
michael@0 2149 GR_GL_OBJECT_LINEAR,
michael@0 2150 components,
michael@0 2151 coefficients));
michael@0 2152 }
michael@0 2153
michael@0 2154 memcpy(fHWTexGenSettings[unitIdx].fCoefficients, coefficients,
michael@0 2155 3 * components * sizeof(GrGLfloat));
michael@0 2156 }
michael@0 2157
michael@0 2158 void GrGpuGL::enableTexGen(int unitIdx, TexGenComponents components, const SkMatrix& matrix) {
michael@0 2159 GrGLfloat coefficients[3 * 3];
michael@0 2160 SkASSERT(this->glCaps().fixedFunctionSupport());
michael@0 2161 SkASSERT(components >= kS_TexGenComponents && components <= kSTR_TexGenComponents);
michael@0 2162
michael@0 2163 coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]);
michael@0 2164 coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]);
michael@0 2165 coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]);
michael@0 2166
michael@0 2167 if (components >= kST_TexGenComponents) {
michael@0 2168 coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]);
michael@0 2169 coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]);
michael@0 2170 coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]);
michael@0 2171 }
michael@0 2172
michael@0 2173 if (components >= kSTR_TexGenComponents) {
michael@0 2174 coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]);
michael@0 2175 coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]);
michael@0 2176 coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]);
michael@0 2177 }
michael@0 2178
michael@0 2179 enableTexGen(unitIdx, components, coefficients);
michael@0 2180 }
michael@0 2181
michael@0 2182 void GrGpuGL::flushTexGenSettings(int numUsedTexCoordSets) {
michael@0 2183 SkASSERT(this->glCaps().fixedFunctionSupport());
michael@0 2184 SkASSERT(this->glCaps().maxFixedFunctionTextureCoords() >= numUsedTexCoordSets);
michael@0 2185
michael@0 2186 // Only write the inactive tex gens, since active tex gens were written
michael@0 2187 // when they were enabled.
michael@0 2188
michael@0 2189 SkDEBUGCODE(
michael@0 2190 for (int i = 0; i < numUsedTexCoordSets; i++) {
michael@0 2191 SkASSERT(0 != fHWTexGenSettings[i].fNumComponents);
michael@0 2192 }
michael@0 2193 );
michael@0 2194
michael@0 2195 for (int i = numUsedTexCoordSets; i < fHWActiveTexGenSets; i++) {
michael@0 2196 SkASSERT(0 != fHWTexGenSettings[i].fNumComponents);
michael@0 2197
michael@0 2198 this->setTextureUnit(i);
michael@0 2199 for (int j = 0; j < fHWTexGenSettings[i].fNumComponents; j++) {
michael@0 2200 GL_CALL(Disable(GR_GL_TEXTURE_GEN_S + j));
michael@0 2201 }
michael@0 2202
michael@0 2203 if (this->caps()->pathRenderingSupport()) {
michael@0 2204 GL_CALL(PathTexGen(GR_GL_TEXTURE0 + i, GR_GL_NONE, 0, NULL));
michael@0 2205 }
michael@0 2206
michael@0 2207 fHWTexGenSettings[i].fNumComponents = 0;
michael@0 2208 }
michael@0 2209
michael@0 2210 fHWActiveTexGenSets = numUsedTexCoordSets;
michael@0 2211 }
michael@0 2212
michael@0 2213 void GrGpuGL::flushMiscFixedFunctionState() {
michael@0 2214
michael@0 2215 const GrDrawState& drawState = this->getDrawState();
michael@0 2216
michael@0 2217 if (drawState.isDitherState()) {
michael@0 2218 if (kYes_TriState != fHWDitherEnabled) {
michael@0 2219 GL_CALL(Enable(GR_GL_DITHER));
michael@0 2220 fHWDitherEnabled = kYes_TriState;
michael@0 2221 }
michael@0 2222 } else {
michael@0 2223 if (kNo_TriState != fHWDitherEnabled) {
michael@0 2224 GL_CALL(Disable(GR_GL_DITHER));
michael@0 2225 fHWDitherEnabled = kNo_TriState;
michael@0 2226 }
michael@0 2227 }
michael@0 2228
michael@0 2229 if (drawState.isColorWriteDisabled()) {
michael@0 2230 if (kNo_TriState != fHWWriteToColor) {
michael@0 2231 GL_CALL(ColorMask(GR_GL_FALSE, GR_GL_FALSE,
michael@0 2232 GR_GL_FALSE, GR_GL_FALSE));
michael@0 2233 fHWWriteToColor = kNo_TriState;
michael@0 2234 }
michael@0 2235 } else {
michael@0 2236 if (kYes_TriState != fHWWriteToColor) {
michael@0 2237 GL_CALL(ColorMask(GR_GL_TRUE, GR_GL_TRUE, GR_GL_TRUE, GR_GL_TRUE));
michael@0 2238 fHWWriteToColor = kYes_TriState;
michael@0 2239 }
michael@0 2240 }
michael@0 2241
michael@0 2242 if (fHWDrawFace != drawState.getDrawFace()) {
michael@0 2243 switch (this->getDrawState().getDrawFace()) {
michael@0 2244 case GrDrawState::kCCW_DrawFace:
michael@0 2245 GL_CALL(Enable(GR_GL_CULL_FACE));
michael@0 2246 GL_CALL(CullFace(GR_GL_BACK));
michael@0 2247 break;
michael@0 2248 case GrDrawState::kCW_DrawFace:
michael@0 2249 GL_CALL(Enable(GR_GL_CULL_FACE));
michael@0 2250 GL_CALL(CullFace(GR_GL_FRONT));
michael@0 2251 break;
michael@0 2252 case GrDrawState::kBoth_DrawFace:
michael@0 2253 GL_CALL(Disable(GR_GL_CULL_FACE));
michael@0 2254 break;
michael@0 2255 default:
michael@0 2256 GrCrash("Unknown draw face.");
michael@0 2257 }
michael@0 2258 fHWDrawFace = drawState.getDrawFace();
michael@0 2259 }
michael@0 2260 }
michael@0 2261
michael@0 2262 void GrGpuGL::notifyRenderTargetDelete(GrRenderTarget* renderTarget) {
michael@0 2263 SkASSERT(NULL != renderTarget);
michael@0 2264 if (fHWBoundRenderTarget == renderTarget) {
michael@0 2265 fHWBoundRenderTarget = NULL;
michael@0 2266 }
michael@0 2267 }
michael@0 2268
michael@0 2269 void GrGpuGL::notifyTextureDelete(GrGLTexture* texture) {
michael@0 2270 for (int s = 0; s < fHWBoundTextures.count(); ++s) {
michael@0 2271 if (fHWBoundTextures[s] == texture) {
michael@0 2272 // deleting bound texture does implied bind to 0
michael@0 2273 fHWBoundTextures[s] = NULL;
michael@0 2274 }
michael@0 2275 }
michael@0 2276 }
michael@0 2277
michael@0 2278 bool GrGpuGL::configToGLFormats(GrPixelConfig config,
michael@0 2279 bool getSizedInternalFormat,
michael@0 2280 GrGLenum* internalFormat,
michael@0 2281 GrGLenum* externalFormat,
michael@0 2282 GrGLenum* externalType) {
michael@0 2283 GrGLenum dontCare;
michael@0 2284 if (NULL == internalFormat) {
michael@0 2285 internalFormat = &dontCare;
michael@0 2286 }
michael@0 2287 if (NULL == externalFormat) {
michael@0 2288 externalFormat = &dontCare;
michael@0 2289 }
michael@0 2290 if (NULL == externalType) {
michael@0 2291 externalType = &dontCare;
michael@0 2292 }
michael@0 2293
michael@0 2294 switch (config) {
michael@0 2295 case kRGBA_8888_GrPixelConfig:
michael@0 2296 *internalFormat = GR_GL_RGBA;
michael@0 2297 *externalFormat = GR_GL_RGBA;
michael@0 2298 if (getSizedInternalFormat) {
michael@0 2299 *internalFormat = GR_GL_RGBA8;
michael@0 2300 } else {
michael@0 2301 *internalFormat = GR_GL_RGBA;
michael@0 2302 }
michael@0 2303 *externalType = GR_GL_UNSIGNED_BYTE;
michael@0 2304 break;
michael@0 2305 case kBGRA_8888_GrPixelConfig:
michael@0 2306 if (!this->glCaps().bgraFormatSupport()) {
michael@0 2307 return false;
michael@0 2308 }
michael@0 2309 if (this->glCaps().bgraIsInternalFormat()) {
michael@0 2310 if (getSizedInternalFormat) {
michael@0 2311 *internalFormat = GR_GL_BGRA8;
michael@0 2312 } else {
michael@0 2313 *internalFormat = GR_GL_BGRA;
michael@0 2314 }
michael@0 2315 } else {
michael@0 2316 if (getSizedInternalFormat) {
michael@0 2317 *internalFormat = GR_GL_RGBA8;
michael@0 2318 } else {
michael@0 2319 *internalFormat = GR_GL_RGBA;
michael@0 2320 }
michael@0 2321 }
michael@0 2322 *externalFormat = GR_GL_BGRA;
michael@0 2323 *externalType = GR_GL_UNSIGNED_BYTE;
michael@0 2324 break;
michael@0 2325 case kRGB_565_GrPixelConfig:
michael@0 2326 *internalFormat = GR_GL_RGB;
michael@0 2327 *externalFormat = GR_GL_RGB;
michael@0 2328 if (getSizedInternalFormat) {
michael@0 2329 if (this->glStandard() == kGL_GrGLStandard) {
michael@0 2330 return false;
michael@0 2331 } else {
michael@0 2332 *internalFormat = GR_GL_RGB565;
michael@0 2333 }
michael@0 2334 } else {
michael@0 2335 *internalFormat = GR_GL_RGB;
michael@0 2336 }
michael@0 2337 *externalType = GR_GL_UNSIGNED_SHORT_5_6_5;
michael@0 2338 break;
michael@0 2339 case kRGBA_4444_GrPixelConfig:
michael@0 2340 *internalFormat = GR_GL_RGBA;
michael@0 2341 *externalFormat = GR_GL_RGBA;
michael@0 2342 if (getSizedInternalFormat) {
michael@0 2343 *internalFormat = GR_GL_RGBA4;
michael@0 2344 } else {
michael@0 2345 *internalFormat = GR_GL_RGBA;
michael@0 2346 }
michael@0 2347 *externalType = GR_GL_UNSIGNED_SHORT_4_4_4_4;
michael@0 2348 break;
michael@0 2349 case kIndex_8_GrPixelConfig:
michael@0 2350 if (this->caps()->eightBitPaletteSupport()) {
michael@0 2351 *internalFormat = GR_GL_PALETTE8_RGBA8;
michael@0 2352 // glCompressedTexImage doesn't take external params
michael@0 2353 *externalFormat = GR_GL_PALETTE8_RGBA8;
michael@0 2354 // no sized/unsized internal format distinction here
michael@0 2355 *internalFormat = GR_GL_PALETTE8_RGBA8;
michael@0 2356 // unused with CompressedTexImage
michael@0 2357 *externalType = GR_GL_UNSIGNED_BYTE;
michael@0 2358 } else {
michael@0 2359 return false;
michael@0 2360 }
michael@0 2361 break;
michael@0 2362 case kAlpha_8_GrPixelConfig:
michael@0 2363 if (this->glCaps().textureRedSupport()) {
michael@0 2364 *internalFormat = GR_GL_RED;
michael@0 2365 *externalFormat = GR_GL_RED;
michael@0 2366 if (getSizedInternalFormat) {
michael@0 2367 *internalFormat = GR_GL_R8;
michael@0 2368 } else {
michael@0 2369 *internalFormat = GR_GL_RED;
michael@0 2370 }
michael@0 2371 *externalType = GR_GL_UNSIGNED_BYTE;
michael@0 2372 } else {
michael@0 2373 *internalFormat = GR_GL_ALPHA;
michael@0 2374 *externalFormat = GR_GL_ALPHA;
michael@0 2375 if (getSizedInternalFormat) {
michael@0 2376 *internalFormat = GR_GL_ALPHA8;
michael@0 2377 } else {
michael@0 2378 *internalFormat = GR_GL_ALPHA;
michael@0 2379 }
michael@0 2380 *externalType = GR_GL_UNSIGNED_BYTE;
michael@0 2381 }
michael@0 2382 break;
michael@0 2383 default:
michael@0 2384 return false;
michael@0 2385 }
michael@0 2386 return true;
michael@0 2387 }
michael@0 2388
michael@0 2389 void GrGpuGL::setTextureUnit(int unit) {
michael@0 2390 SkASSERT(unit >= 0 && unit < fHWBoundTextures.count());
michael@0 2391 if (unit != fHWActiveTextureUnitIdx) {
michael@0 2392 GL_CALL(ActiveTexture(GR_GL_TEXTURE0 + unit));
michael@0 2393 fHWActiveTextureUnitIdx = unit;
michael@0 2394 }
michael@0 2395 }
michael@0 2396
michael@0 2397 void GrGpuGL::setScratchTextureUnit() {
michael@0 2398 // Bind the last texture unit since it is the least likely to be used by GrGLProgram.
michael@0 2399 int lastUnitIdx = fHWBoundTextures.count() - 1;
michael@0 2400 if (lastUnitIdx != fHWActiveTextureUnitIdx) {
michael@0 2401 GL_CALL(ActiveTexture(GR_GL_TEXTURE0 + lastUnitIdx));
michael@0 2402 fHWActiveTextureUnitIdx = lastUnitIdx;
michael@0 2403 }
michael@0 2404 // clear out the this field so that if a program does use this unit it will rebind the correct
michael@0 2405 // texture.
michael@0 2406 fHWBoundTextures[lastUnitIdx] = NULL;
michael@0 2407 }
michael@0 2408
michael@0 2409 namespace {
michael@0 2410 // Determines whether glBlitFramebuffer could be used between src and dst.
michael@0 2411 inline bool can_blit_framebuffer(const GrSurface* dst,
michael@0 2412 const GrSurface* src,
michael@0 2413 const GrGpuGL* gpu,
michael@0 2414 bool* wouldNeedTempFBO = NULL) {
michael@0 2415 if (gpu->glCaps().isConfigRenderable(dst->config(), dst->desc().fSampleCnt > 0) &&
michael@0 2416 gpu->glCaps().isConfigRenderable(src->config(), src->desc().fSampleCnt > 0) &&
michael@0 2417 gpu->glCaps().usesMSAARenderBuffers()) {
michael@0 2418 // ES3 doesn't allow framebuffer blits when the src has MSAA and the configs don't match
michael@0 2419 // or the rects are not the same (not just the same size but have the same edges).
michael@0 2420 if (GrGLCaps::kES_3_0_MSFBOType == gpu->glCaps().msFBOType() &&
michael@0 2421 (src->desc().fSampleCnt > 0 || src->config() != dst->config())) {
michael@0 2422 return false;
michael@0 2423 }
michael@0 2424 if (NULL != wouldNeedTempFBO) {
michael@0 2425 *wouldNeedTempFBO = NULL == dst->asRenderTarget() || NULL == src->asRenderTarget();
michael@0 2426 }
michael@0 2427 return true;
michael@0 2428 } else {
michael@0 2429 return false;
michael@0 2430 }
michael@0 2431 }
michael@0 2432
michael@0 2433 inline bool can_copy_texsubimage(const GrSurface* dst,
michael@0 2434 const GrSurface* src,
michael@0 2435 const GrGpuGL* gpu,
michael@0 2436 bool* wouldNeedTempFBO = NULL) {
michael@0 2437 // Table 3.9 of the ES2 spec indicates the supported formats with CopyTexSubImage
michael@0 2438 // and BGRA isn't in the spec. There doesn't appear to be any extension that adds it. Perhaps
michael@0 2439 // many drivers would allow it to work, but ANGLE does not.
michael@0 2440 if (kGLES_GrGLStandard == gpu->glStandard() && gpu->glCaps().bgraIsInternalFormat() &&
michael@0 2441 (kBGRA_8888_GrPixelConfig == dst->config() || kBGRA_8888_GrPixelConfig == src->config())) {
michael@0 2442 return false;
michael@0 2443 }
michael@0 2444 const GrGLRenderTarget* dstRT = static_cast<const GrGLRenderTarget*>(dst->asRenderTarget());
michael@0 2445 // If dst is multisampled (and uses an extension where there is a separate MSAA renderbuffer)
michael@0 2446 // then we don't want to copy to the texture but to the MSAA buffer.
michael@0 2447 if (NULL != dstRT && dstRT->renderFBOID() != dstRT->textureFBOID()) {
michael@0 2448 return false;
michael@0 2449 }
michael@0 2450 const GrGLRenderTarget* srcRT = static_cast<const GrGLRenderTarget*>(src->asRenderTarget());
michael@0 2451 // If the src is multisampled (and uses an extension where there is a separate MSAA
michael@0 2452 // renderbuffer) then it is an invalid operation to call CopyTexSubImage
michael@0 2453 if (NULL != srcRT && srcRT->renderFBOID() != srcRT->textureFBOID()) {
michael@0 2454 return false;
michael@0 2455 }
michael@0 2456 if (gpu->glCaps().isConfigRenderable(src->config(), src->desc().fSampleCnt > 0) &&
michael@0 2457 NULL != dst->asTexture() &&
michael@0 2458 dst->origin() == src->origin() &&
michael@0 2459 kIndex_8_GrPixelConfig != src->config()) {
michael@0 2460 if (NULL != wouldNeedTempFBO) {
michael@0 2461 *wouldNeedTempFBO = NULL == src->asRenderTarget();
michael@0 2462 }
michael@0 2463 return true;
michael@0 2464 } else {
michael@0 2465 return false;
michael@0 2466 }
michael@0 2467 }
michael@0 2468
michael@0 2469 // If a temporary FBO was created, its non-zero ID is returned. The viewport that the copy rect is
michael@0 2470 // relative to is output.
michael@0 2471 inline GrGLuint bind_surface_as_fbo(const GrGLInterface* gl,
michael@0 2472 GrSurface* surface,
michael@0 2473 GrGLenum fboTarget,
michael@0 2474 GrGLIRect* viewport) {
michael@0 2475 GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(surface->asRenderTarget());
michael@0 2476 GrGLuint tempFBOID;
michael@0 2477 if (NULL == rt) {
michael@0 2478 SkASSERT(NULL != surface->asTexture());
michael@0 2479 GrGLuint texID = static_cast<GrGLTexture*>(surface->asTexture())->textureID();
michael@0 2480 GR_GL_CALL(gl, GenFramebuffers(1, &tempFBOID));
michael@0 2481 GR_GL_CALL(gl, BindFramebuffer(fboTarget, tempFBOID));
michael@0 2482 GR_GL_CALL(gl, FramebufferTexture2D(fboTarget,
michael@0 2483 GR_GL_COLOR_ATTACHMENT0,
michael@0 2484 GR_GL_TEXTURE_2D,
michael@0 2485 texID,
michael@0 2486 0));
michael@0 2487 viewport->fLeft = 0;
michael@0 2488 viewport->fBottom = 0;
michael@0 2489 viewport->fWidth = surface->width();
michael@0 2490 viewport->fHeight = surface->height();
michael@0 2491 } else {
michael@0 2492 tempFBOID = 0;
michael@0 2493 GR_GL_CALL(gl, BindFramebuffer(fboTarget, rt->renderFBOID()));
michael@0 2494 *viewport = rt->getViewport();
michael@0 2495 }
michael@0 2496 return tempFBOID;
michael@0 2497 }
michael@0 2498
michael@0 2499 }
michael@0 2500
michael@0 2501 void GrGpuGL::initCopySurfaceDstDesc(const GrSurface* src, GrTextureDesc* desc) {
michael@0 2502 // Check for format issues with glCopyTexSubImage2D
michael@0 2503 if (kGLES_GrGLStandard == this->glStandard() && this->glCaps().bgraIsInternalFormat() &&
michael@0 2504 kBGRA_8888_GrPixelConfig == src->config()) {
michael@0 2505 // glCopyTexSubImage2D doesn't work with this config. We'll want to make it a render target
michael@0 2506 // in order to call glBlitFramebuffer or to copy to it by rendering.
michael@0 2507 INHERITED::initCopySurfaceDstDesc(src, desc);
michael@0 2508 return;
michael@0 2509 } else if (NULL == src->asRenderTarget()) {
michael@0 2510 // We don't want to have to create an FBO just to use glCopyTexSubImage2D. Let the base
michael@0 2511 // class handle it by rendering.
michael@0 2512 INHERITED::initCopySurfaceDstDesc(src, desc);
michael@0 2513 return;
michael@0 2514 }
michael@0 2515
michael@0 2516 const GrGLRenderTarget* srcRT = static_cast<const GrGLRenderTarget*>(src->asRenderTarget());
michael@0 2517 if (NULL != srcRT && srcRT->renderFBOID() != srcRT->textureFBOID()) {
michael@0 2518 // It's illegal to call CopyTexSubImage2D on a MSAA renderbuffer.
michael@0 2519 INHERITED::initCopySurfaceDstDesc(src, desc);
michael@0 2520 } else {
michael@0 2521 desc->fConfig = src->config();
michael@0 2522 desc->fOrigin = src->origin();
michael@0 2523 desc->fFlags = kNone_GrTextureFlags;
michael@0 2524 }
michael@0 2525 }
michael@0 2526
michael@0 2527 bool GrGpuGL::onCopySurface(GrSurface* dst,
michael@0 2528 GrSurface* src,
michael@0 2529 const SkIRect& srcRect,
michael@0 2530 const SkIPoint& dstPoint) {
michael@0 2531 bool inheritedCouldCopy = INHERITED::onCanCopySurface(dst, src, srcRect, dstPoint);
michael@0 2532 bool copied = false;
michael@0 2533 bool wouldNeedTempFBO = false;
michael@0 2534 if (can_copy_texsubimage(dst, src, this, &wouldNeedTempFBO) &&
michael@0 2535 (!wouldNeedTempFBO || !inheritedCouldCopy)) {
michael@0 2536 GrGLuint srcFBO;
michael@0 2537 GrGLIRect srcVP;
michael@0 2538 srcFBO = bind_surface_as_fbo(this->glInterface(), src, GR_GL_FRAMEBUFFER, &srcVP);
michael@0 2539 GrGLTexture* dstTex = static_cast<GrGLTexture*>(dst->asTexture());
michael@0 2540 SkASSERT(NULL != dstTex);
michael@0 2541 // We modified the bound FBO
michael@0 2542 fHWBoundRenderTarget = NULL;
michael@0 2543 GrGLIRect srcGLRect;
michael@0 2544 srcGLRect.setRelativeTo(srcVP,
michael@0 2545 srcRect.fLeft,
michael@0 2546 srcRect.fTop,
michael@0 2547 srcRect.width(),
michael@0 2548 srcRect.height(),
michael@0 2549 src->origin());
michael@0 2550
michael@0 2551 this->setScratchTextureUnit();
michael@0 2552 GL_CALL(BindTexture(GR_GL_TEXTURE_2D, dstTex->textureID()));
michael@0 2553 GrGLint dstY;
michael@0 2554 if (kBottomLeft_GrSurfaceOrigin == dst->origin()) {
michael@0 2555 dstY = dst->height() - (dstPoint.fY + srcGLRect.fHeight);
michael@0 2556 } else {
michael@0 2557 dstY = dstPoint.fY;
michael@0 2558 }
michael@0 2559 GL_CALL(CopyTexSubImage2D(GR_GL_TEXTURE_2D, 0,
michael@0 2560 dstPoint.fX, dstY,
michael@0 2561 srcGLRect.fLeft, srcGLRect.fBottom,
michael@0 2562 srcGLRect.fWidth, srcGLRect.fHeight));
michael@0 2563 copied = true;
michael@0 2564 if (srcFBO) {
michael@0 2565 GL_CALL(DeleteFramebuffers(1, &srcFBO));
michael@0 2566 }
michael@0 2567 } else if (can_blit_framebuffer(dst, src, this, &wouldNeedTempFBO) &&
michael@0 2568 (!wouldNeedTempFBO || !inheritedCouldCopy)) {
michael@0 2569 SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
michael@0 2570 srcRect.width(), srcRect.height());
michael@0 2571 bool selfOverlap = false;
michael@0 2572 if (dst->isSameAs(src)) {
michael@0 2573 selfOverlap = SkIRect::IntersectsNoEmptyCheck(dstRect, srcRect);
michael@0 2574 }
michael@0 2575
michael@0 2576 if (!selfOverlap) {
michael@0 2577 GrGLuint dstFBO;
michael@0 2578 GrGLuint srcFBO;
michael@0 2579 GrGLIRect dstVP;
michael@0 2580 GrGLIRect srcVP;
michael@0 2581 dstFBO = bind_surface_as_fbo(this->glInterface(), dst, GR_GL_DRAW_FRAMEBUFFER, &dstVP);
michael@0 2582 srcFBO = bind_surface_as_fbo(this->glInterface(), src, GR_GL_READ_FRAMEBUFFER, &srcVP);
michael@0 2583 // We modified the bound FBO
michael@0 2584 fHWBoundRenderTarget = NULL;
michael@0 2585 GrGLIRect srcGLRect;
michael@0 2586 GrGLIRect dstGLRect;
michael@0 2587 srcGLRect.setRelativeTo(srcVP,
michael@0 2588 srcRect.fLeft,
michael@0 2589 srcRect.fTop,
michael@0 2590 srcRect.width(),
michael@0 2591 srcRect.height(),
michael@0 2592 src->origin());
michael@0 2593 dstGLRect.setRelativeTo(dstVP,
michael@0 2594 dstRect.fLeft,
michael@0 2595 dstRect.fTop,
michael@0 2596 dstRect.width(),
michael@0 2597 dstRect.height(),
michael@0 2598 dst->origin());
michael@0 2599
michael@0 2600 GrAutoTRestore<ScissorState> asr;
michael@0 2601 if (GrGLCaps::kDesktop_EXT_MSFBOType == this->glCaps().msFBOType()) {
michael@0 2602 // The EXT version applies the scissor during the blit, so disable it.
michael@0 2603 asr.reset(&fScissorState);
michael@0 2604 fScissorState.fEnabled = false;
michael@0 2605 this->flushScissor();
michael@0 2606 }
michael@0 2607 GrGLint srcY0;
michael@0 2608 GrGLint srcY1;
michael@0 2609 // Does the blit need to y-mirror or not?
michael@0 2610 if (src->origin() == dst->origin()) {
michael@0 2611 srcY0 = srcGLRect.fBottom;
michael@0 2612 srcY1 = srcGLRect.fBottom + srcGLRect.fHeight;
michael@0 2613 } else {
michael@0 2614 srcY0 = srcGLRect.fBottom + srcGLRect.fHeight;
michael@0 2615 srcY1 = srcGLRect.fBottom;
michael@0 2616 }
michael@0 2617 GL_CALL(BlitFramebuffer(srcGLRect.fLeft,
michael@0 2618 srcY0,
michael@0 2619 srcGLRect.fLeft + srcGLRect.fWidth,
michael@0 2620 srcY1,
michael@0 2621 dstGLRect.fLeft,
michael@0 2622 dstGLRect.fBottom,
michael@0 2623 dstGLRect.fLeft + dstGLRect.fWidth,
michael@0 2624 dstGLRect.fBottom + dstGLRect.fHeight,
michael@0 2625 GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST));
michael@0 2626 if (dstFBO) {
michael@0 2627 GL_CALL(DeleteFramebuffers(1, &dstFBO));
michael@0 2628 }
michael@0 2629 if (srcFBO) {
michael@0 2630 GL_CALL(DeleteFramebuffers(1, &srcFBO));
michael@0 2631 }
michael@0 2632 copied = true;
michael@0 2633 }
michael@0 2634 }
michael@0 2635 if (!copied && inheritedCouldCopy) {
michael@0 2636 copied = INHERITED::onCopySurface(dst, src, srcRect, dstPoint);
michael@0 2637 SkASSERT(copied);
michael@0 2638 }
michael@0 2639 return copied;
michael@0 2640 }
michael@0 2641
michael@0 2642 bool GrGpuGL::onCanCopySurface(GrSurface* dst,
michael@0 2643 GrSurface* src,
michael@0 2644 const SkIRect& srcRect,
michael@0 2645 const SkIPoint& dstPoint) {
michael@0 2646 // This mirrors the logic in onCopySurface.
michael@0 2647 if (can_copy_texsubimage(dst, src, this)) {
michael@0 2648 return true;
michael@0 2649 }
michael@0 2650 if (can_blit_framebuffer(dst, src, this)) {
michael@0 2651 if (dst->isSameAs(src)) {
michael@0 2652 SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
michael@0 2653 srcRect.width(), srcRect.height());
michael@0 2654 if(!SkIRect::IntersectsNoEmptyCheck(dstRect, srcRect)) {
michael@0 2655 return true;
michael@0 2656 }
michael@0 2657 } else {
michael@0 2658 return true;
michael@0 2659 }
michael@0 2660 }
michael@0 2661 return INHERITED::onCanCopySurface(dst, src, srcRect, dstPoint);
michael@0 2662 }
michael@0 2663
michael@0 2664 void GrGpuGL::onInstantGpuTraceEvent(const char* marker) {
michael@0 2665 if (this->caps()->gpuTracingSupport()) {
michael@0 2666 // GL_CALL(InsertEventMarker(0, marker));
michael@0 2667 }
michael@0 2668 }
michael@0 2669
michael@0 2670 void GrGpuGL::onPushGpuTraceEvent(const char* marker) {
michael@0 2671 if (this->caps()->gpuTracingSupport()) {
michael@0 2672 // GL_CALL(PushGroupMarker(0, marker));
michael@0 2673 }
michael@0 2674 }
michael@0 2675
michael@0 2676 void GrGpuGL::onPopGpuTraceEvent() {
michael@0 2677 if (this->caps()->gpuTracingSupport()) {
michael@0 2678 // GL_CALL(PopGroupMarker());
michael@0 2679 }
michael@0 2680 }
michael@0 2681
michael@0 2682 ///////////////////////////////////////////////////////////////////////////////
michael@0 2683
michael@0 2684 GrGLAttribArrayState* GrGpuGL::HWGeometryState::bindArrayAndBuffersToDraw(
michael@0 2685 GrGpuGL* gpu,
michael@0 2686 const GrGLVertexBuffer* vbuffer,
michael@0 2687 const GrGLIndexBuffer* ibuffer) {
michael@0 2688 SkASSERT(NULL != vbuffer);
michael@0 2689 GrGLAttribArrayState* attribState;
michael@0 2690
michael@0 2691 // We use a vertex array if we're on a core profile and the verts are in a VBO.
michael@0 2692 if (gpu->glCaps().isCoreProfile() && !vbuffer->isCPUBacked()) {
michael@0 2693 if (NULL == fVBOVertexArray || !fVBOVertexArray->isValid()) {
michael@0 2694 SkSafeUnref(fVBOVertexArray);
michael@0 2695 GrGLuint arrayID;
michael@0 2696 GR_GL_CALL(gpu->glInterface(), GenVertexArrays(1, &arrayID));
michael@0 2697 int attrCount = gpu->glCaps().maxVertexAttributes();
michael@0 2698 fVBOVertexArray = SkNEW_ARGS(GrGLVertexArray, (gpu, arrayID, attrCount));
michael@0 2699 }
michael@0 2700 attribState = fVBOVertexArray->bindWithIndexBuffer(ibuffer);
michael@0 2701 } else {
michael@0 2702 if (NULL != ibuffer) {
michael@0 2703 this->setIndexBufferIDOnDefaultVertexArray(gpu, ibuffer->bufferID());
michael@0 2704 } else {
michael@0 2705 this->setVertexArrayID(gpu, 0);
michael@0 2706 }
michael@0 2707 int attrCount = gpu->glCaps().maxVertexAttributes();
michael@0 2708 if (fDefaultVertexArrayAttribState.count() != attrCount) {
michael@0 2709 fDefaultVertexArrayAttribState.resize(attrCount);
michael@0 2710 }
michael@0 2711 attribState = &fDefaultVertexArrayAttribState;
michael@0 2712 }
michael@0 2713 return attribState;
michael@0 2714 }

mercurial