| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 | 8 |
| 9 #include "GrGLGpu.h" | 9 #include "GrGLGpu.h" |
| 10 #include "GrGLGLSL.h" | 10 #include "GrGLGLSL.h" |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 180 return nullptr; | 180 return nullptr; |
| 181 } | 181 } |
| 182 | 182 |
| 183 static bool gPrintStartupSpew; | 183 static bool gPrintStartupSpew; |
| 184 | 184 |
| 185 GrGLGpu::GrGLGpu(GrGLContext* ctx, GrContext* context) | 185 GrGLGpu::GrGLGpu(GrGLContext* ctx, GrContext* context) |
| 186 : GrGpu(context) | 186 : GrGpu(context) |
| 187 , fGLContext(ctx) { | 187 , fGLContext(ctx) { |
| 188 SkASSERT(ctx); | 188 SkASSERT(ctx); |
| 189 fCaps.reset(SkRef(ctx->caps())); | 189 fCaps.reset(SkRef(ctx->caps())); |
| 190 this->generateConfigTable(); | |
| 191 | 190 |
| 192 fHWBoundTextureUniqueIDs.reset(this->glCaps().maxFragmentTextureUnits()); | 191 fHWBoundTextureUniqueIDs.reset(this->glCaps().maxFragmentTextureUnits()); |
| 193 | 192 |
| 194 GrGLClearErr(this->glInterface()); | 193 GrGLClearErr(this->glInterface()); |
| 195 if (gPrintStartupSpew) { | 194 if (gPrintStartupSpew) { |
| 196 const GrGLubyte* vendor; | 195 const GrGLubyte* vendor; |
| 197 const GrGLubyte* renderer; | 196 const GrGLubyte* renderer; |
| 198 const GrGLubyte* version; | 197 const GrGLubyte* version; |
| 199 GL_CALL_RET(vendor, GetString(GR_GL_VENDOR)); | 198 GL_CALL_RET(vendor, GetString(GR_GL_VENDOR)); |
| 200 GL_CALL_RET(renderer, GetString(GR_GL_RENDERER)); | 199 GL_CALL_RET(renderer, GetString(GR_GL_RENDERER)); |
| (...skipping 487 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 688 | 687 |
| 689 // in case we need a temporary, trimmed copy of the src pixels | 688 // in case we need a temporary, trimmed copy of the src pixels |
| 690 #if defined(GOOGLE3) | 689 #if defined(GOOGLE3) |
| 691 // Stack frame size is limited in GOOGLE3. | 690 // Stack frame size is limited in GOOGLE3. |
| 692 SkAutoSMalloc<64 * 128> tempStorage; | 691 SkAutoSMalloc<64 * 128> tempStorage; |
| 693 #else | 692 #else |
| 694 SkAutoSMalloc<128 * 128> tempStorage; | 693 SkAutoSMalloc<128 * 128> tempStorage; |
| 695 #endif | 694 #endif |
| 696 | 695 |
| 697 // Internal format comes from the texture desc. | 696 // Internal format comes from the texture desc. |
| 698 GrGLenum internalFormat = fConfigTable[desc.fConfig].fInternalFormatTexImage
; | 697 GrGLenum internalFormat = |
| 698 this->glCaps().configGLFormats(desc.fConfig).fInternalFormatTexImage; |
| 699 | 699 |
| 700 // External format and type come from the upload data. | 700 // External format and type come from the upload data. |
| 701 GrGLenum externalFormat = fConfigTable[dataConfig].fExternalFormatForTexImag
e; | 701 GrGLenum externalFormat = |
| 702 GrGLenum externalType = fConfigTable[dataConfig].fExternalType; | 702 this->glCaps().configGLFormats(dataConfig).fExternalFormatForTexImage; |
| 703 GrGLenum externalType = this->glCaps().configGLFormats(dataConfig).fExternal
Type; |
| 703 | 704 |
| 704 /* | 705 /* |
| 705 * Check whether to allocate a temporary buffer for flipping y or | 706 * Check whether to allocate a temporary buffer for flipping y or |
| 706 * because our srcData has extra bytes past each row. If so, we need | 707 * because our srcData has extra bytes past each row. If so, we need |
| 707 * to trim those off here, since GL ES may not let us specify | 708 * to trim those off here, since GL ES may not let us specify |
| 708 * GL_UNPACK_ROW_LENGTH. | 709 * GL_UNPACK_ROW_LENGTH. |
| 709 */ | 710 */ |
| 710 bool restoreGLRowLength = false; | 711 bool restoreGLRowLength = false; |
| 711 bool swFlipY = false; | 712 bool swFlipY = false; |
| 712 bool glFlipY = false; | 713 bool glFlipY = false; |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 820 SkASSERT(height <= desc.fHeight); | 821 SkASSERT(height <= desc.fHeight); |
| 821 } | 822 } |
| 822 #endif | 823 #endif |
| 823 | 824 |
| 824 // Make sure that the width and height that we pass to OpenGL | 825 // Make sure that the width and height that we pass to OpenGL |
| 825 // is a multiple of the block size. | 826 // is a multiple of the block size. |
| 826 size_t dataSize = GrCompressedFormatDataSize(desc.fConfig, width, height); | 827 size_t dataSize = GrCompressedFormatDataSize(desc.fConfig, width, height); |
| 827 | 828 |
| 828 // We only need the internal format for compressed 2D textures. There is on | 829 // We only need the internal format for compressed 2D textures. There is on |
| 829 // sized vs base internal format distinction for compressed textures. | 830 // sized vs base internal format distinction for compressed textures. |
| 830 GrGLenum internalFormat = fConfigTable[desc.fConfig].fSizedInternalFormat; | 831 GrGLenum internalFormat =this->glCaps().configGLFormats(desc.fConfig).fSized
InternalFormat; |
| 831 | 832 |
| 832 if (isNewTexture) { | 833 if (isNewTexture) { |
| 833 CLEAR_ERROR_BEFORE_ALLOC(this->glInterface()); | 834 CLEAR_ERROR_BEFORE_ALLOC(this->glInterface()); |
| 834 GL_ALLOC_CALL(this->glInterface(), | 835 GL_ALLOC_CALL(this->glInterface(), |
| 835 CompressedTexImage2D(target, | 836 CompressedTexImage2D(target, |
| 836 0, // level | 837 0, // level |
| 837 internalFormat, | 838 internalFormat, |
| 838 width, height, | 839 width, height, |
| 839 0, // border | 840 0, // border |
| 840 SkToInt(dataSize), | 841 SkToInt(dataSize), |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 932 GL_CALL(GenFramebuffers(1, &idDesc->fRTFBOID)); | 933 GL_CALL(GenFramebuffers(1, &idDesc->fRTFBOID)); |
| 933 GL_CALL(GenRenderbuffers(1, &idDesc->fMSColorRenderbufferID)); | 934 GL_CALL(GenRenderbuffers(1, &idDesc->fMSColorRenderbufferID)); |
| 934 if (!idDesc->fRTFBOID || | 935 if (!idDesc->fRTFBOID || |
| 935 !idDesc->fMSColorRenderbufferID) { | 936 !idDesc->fMSColorRenderbufferID) { |
| 936 goto FAILED; | 937 goto FAILED; |
| 937 } | 938 } |
| 938 // All ES versions (thus far) require sized internal formats for render
buffers. | 939 // All ES versions (thus far) require sized internal formats for render
buffers. |
| 939 // TODO: Always use sized internal format? | 940 // TODO: Always use sized internal format? |
| 940 // If this rule gets more complicated, add a field to ConfigEntry rather
than logic here. | 941 // If this rule gets more complicated, add a field to ConfigEntry rather
than logic here. |
| 941 colorRenderbufferFormat = kGLES_GrGLStandard == this->glStandard() ? | 942 colorRenderbufferFormat = kGLES_GrGLStandard == this->glStandard() ? |
| 942 fConfigTable[desc.fConfig].fSize
dInternalFormat : | 943 this->glCaps().configGLFormats(desc.fConfig).fSizedI
nternalFormat : |
| 943 fConfigTable[desc.fConfig].fBase
InternalFormat; | 944 this->glCaps().configGLFormats(desc.fConfig).fBaseIn
ternalFormat; |
| 944 } else { | 945 } else { |
| 945 idDesc->fRTFBOID = idDesc->fTexFBOID; | 946 idDesc->fRTFBOID = idDesc->fTexFBOID; |
| 946 } | 947 } |
| 947 | 948 |
| 948 // below here we may bind the FBO | 949 // below here we may bind the FBO |
| 949 fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; | 950 fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; |
| 950 if (idDesc->fRTFBOID != idDesc->fTexFBOID) { | 951 if (idDesc->fRTFBOID != idDesc->fTexFBOID) { |
| 951 SkASSERT(desc.fSampleCnt > 0); | 952 SkASSERT(desc.fSampleCnt > 0); |
| 952 GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, idDesc->fMSColorRenderbuffe
rID)); | 953 GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, idDesc->fMSColorRenderbuffe
rID)); |
| 953 if (!renderbuffer_storage_msaa(*fGLContext, | 954 if (!renderbuffer_storage_msaa(*fGLContext, |
| (...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1186 } else { | 1187 } else { |
| 1187 format->fTotalBits = format->fStencilBits; | 1188 format->fTotalBits = format->fStencilBits; |
| 1188 } | 1189 } |
| 1189 } | 1190 } |
| 1190 } | 1191 } |
| 1191 } | 1192 } |
| 1192 | 1193 |
| 1193 int GrGLGpu::getCompatibleStencilIndex(GrPixelConfig config) { | 1194 int GrGLGpu::getCompatibleStencilIndex(GrPixelConfig config) { |
| 1194 static const int kSize = 16; | 1195 static const int kSize = 16; |
| 1195 SkASSERT(this->caps()->isConfigRenderable(config, false)); | 1196 SkASSERT(this->caps()->isConfigRenderable(config, false)); |
| 1196 if (ConfigEntry::kUnknown_StencilIndex == fConfigTable[config].fStencilForma
tIndex) { | 1197 if (!this->glCaps().hasStencilFormatBeenDeterminedForConfig(config)) { |
| 1197 // Default to unsupported | 1198 // Default to unsupported, set this if we find a stencil format that wor
ks. |
| 1198 fConfigTable[config].fStencilFormatIndex = ConfigEntry::kUnsupported_Ste
ncilFormatIndex; | 1199 int firstWorkingStencilFormatIndex = -1; |
| 1199 // Create color texture | 1200 // Create color texture |
| 1200 GrGLuint colorID = 0; | 1201 GrGLuint colorID = 0; |
| 1201 GL_CALL(GenTextures(1, &colorID)); | 1202 GL_CALL(GenTextures(1, &colorID)); |
| 1202 this->setScratchTextureUnit(); | 1203 this->setScratchTextureUnit(); |
| 1203 GL_CALL(BindTexture(GR_GL_TEXTURE_2D, colorID)); | 1204 GL_CALL(BindTexture(GR_GL_TEXTURE_2D, colorID)); |
| 1204 GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, | 1205 GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, |
| 1205 GR_GL_TEXTURE_MAG_FILTER, | 1206 GR_GL_TEXTURE_MAG_FILTER, |
| 1206 GR_GL_NEAREST)); | 1207 GR_GL_NEAREST)); |
| 1207 GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, | 1208 GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, |
| 1208 GR_GL_TEXTURE_MIN_FILTER, | 1209 GR_GL_TEXTURE_MIN_FILTER, |
| 1209 GR_GL_NEAREST)); | 1210 GR_GL_NEAREST)); |
| 1210 GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, | 1211 GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, |
| 1211 GR_GL_TEXTURE_WRAP_S, | 1212 GR_GL_TEXTURE_WRAP_S, |
| 1212 GR_GL_CLAMP_TO_EDGE)); | 1213 GR_GL_CLAMP_TO_EDGE)); |
| 1213 GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, | 1214 GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, |
| 1214 GR_GL_TEXTURE_WRAP_T, | 1215 GR_GL_TEXTURE_WRAP_T, |
| 1215 GR_GL_CLAMP_TO_EDGE)); | 1216 GR_GL_CLAMP_TO_EDGE)); |
| 1216 | 1217 |
| 1217 GrGLenum internalFormat = fConfigTable[config].fInternalFormatTexImage; | 1218 const GrGLCaps::ConfigFormats colorFormats = this->glCaps().configGLForm
ats(config); |
| 1218 GrGLenum externalFormat = fConfigTable[config].fExternalFormatForTexImag
e; | |
| 1219 GrGLenum externalType = fConfigTable[config].fExternalType; | |
| 1220 | 1219 |
| 1221 CLEAR_ERROR_BEFORE_ALLOC(this->glInterface()); | 1220 CLEAR_ERROR_BEFORE_ALLOC(this->glInterface()); |
| 1222 GL_ALLOC_CALL(this->glInterface(), TexImage2D(GR_GL_TEXTURE_2D, | 1221 GL_ALLOC_CALL(this->glInterface(), TexImage2D(GR_GL_TEXTURE_2D, |
| 1223 0, | 1222 0, |
| 1224 internalFormat, | 1223 colorFormats.fInternalForm
atTexImage, |
| 1225 kSize, | 1224 kSize, |
| 1226 kSize, | 1225 kSize, |
| 1227 0, | 1226 0, |
| 1228 externalFormat, | 1227 colorFormats.fExternalForm
atForTexImage, |
| 1229 externalType, | 1228 colorFormats.fExternalType
, |
| 1230 NULL)); | 1229 NULL)); |
| 1231 if (GR_GL_NO_ERROR != GR_GL_GET_ERROR(this->glInterface())) { | 1230 if (GR_GL_NO_ERROR != CHECK_ALLOC_ERROR(this->glInterface())) { |
| 1232 GL_CALL(DeleteTextures(1, &colorID)); | 1231 GL_CALL(DeleteTextures(1, &colorID)); |
| 1233 return ConfigEntry::kUnsupported_StencilFormatIndex; | 1232 return -1; |
| 1234 } | 1233 } |
| 1235 | 1234 |
| 1236 // unbind the texture from the texture unit before binding it to the fra
me buffer | 1235 // unbind the texture from the texture unit before binding it to the fra
me buffer |
| 1237 GL_CALL(BindTexture(GR_GL_TEXTURE_2D, 0)); | 1236 GL_CALL(BindTexture(GR_GL_TEXTURE_2D, 0)); |
| 1238 | 1237 |
| 1239 // Create Framebuffer | 1238 // Create Framebuffer |
| 1240 GrGLuint fb = 0; | 1239 GrGLuint fb = 0; |
| 1241 GL_CALL(GenFramebuffers(1, &fb)); | 1240 GL_CALL(GenFramebuffers(1, &fb)); |
| 1242 GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fb)); | 1241 GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fb)); |
| 1243 fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; | 1242 fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID; |
| 1244 GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER, | 1243 GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER, |
| 1245 GR_GL_COLOR_ATTACHMENT0, | 1244 GR_GL_COLOR_ATTACHMENT0, |
| 1246 GR_GL_TEXTURE_2D, | 1245 GR_GL_TEXTURE_2D, |
| 1247 colorID, | 1246 colorID, |
| 1248 0)); | 1247 0)); |
| 1248 GrGLuint sbRBID = 0; |
| 1249 GL_CALL(GenRenderbuffers(1, &sbRBID)); |
| 1249 | 1250 |
| 1250 // look over formats till I find a compatible one | 1251 // look over formats till I find a compatible one |
| 1251 int stencilFmtCnt = this->glCaps().stencilFormats().count(); | 1252 int stencilFmtCnt = this->glCaps().stencilFormats().count(); |
| 1252 GrGLuint sbRBID = 0; | 1253 if (sbRBID) { |
| 1253 for (int i = 0; i < stencilFmtCnt; ++i) { | |
| 1254 const GrGLCaps::StencilFormat& sFmt = this->glCaps().stencilFormats(
)[i]; | |
| 1255 | |
| 1256 GL_CALL(GenRenderbuffers(1, &sbRBID)); | |
| 1257 if (!sbRBID) { | |
| 1258 break; | |
| 1259 } | |
| 1260 GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, sbRBID)); | 1254 GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, sbRBID)); |
| 1261 CLEAR_ERROR_BEFORE_ALLOC(this->glInterface()); | 1255 for (int i = 0; i < stencilFmtCnt && sbRBID; ++i) { |
| 1262 GL_ALLOC_CALL(this->glInterface(), RenderbufferStorage(GR_GL_RENDERB
UFFER, | 1256 const GrGLCaps::StencilFormat& sFmt = this->glCaps().stencilForm
ats()[i]; |
| 1263 sFmt.fInterna
lFormat, | 1257 CLEAR_ERROR_BEFORE_ALLOC(this->glInterface()); |
| 1264 kSize, kSize)
); | 1258 GL_ALLOC_CALL(this->glInterface(), RenderbufferStorage(GR_GL_REN
DERBUFFER, |
| 1265 if (GR_GL_NO_ERROR == GR_GL_GET_ERROR(this->glInterface())) { | 1259 sFmt.fInt
ernalFormat, |
| 1266 GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, | 1260 kSize, kS
ize)); |
| 1267 GR_GL_STENCIL_ATTACHMENT, | 1261 if (GR_GL_NO_ERROR == CHECK_ALLOC_ERROR(this->glInterface())) { |
| 1268 GR_GL_RENDERBUFFER, sbRBID)); | |
| 1269 if (sFmt.fPacked) { | |
| 1270 GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, | 1262 GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, |
| 1271 GR_GL_DEPTH_ATTACHMENT, | 1263 GR_GL_STENCIL_ATTACHMENT, |
| 1272 GR_GL_RENDERBUFFER, sbRBID))
; | 1264 GR_GL_RENDERBUFFER, sbRBID))
; |
| 1273 } else { | 1265 if (sFmt.fPacked) { |
| 1274 GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, | 1266 GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, |
| 1275 GR_GL_DEPTH_ATTACHMENT, | 1267 GR_GL_DEPTH_ATTACHMENT, |
| 1276 GR_GL_RENDERBUFFER, 0)); | 1268 GR_GL_RENDERBUFFER, sbRB
ID)); |
| 1277 } | 1269 } else { |
| 1278 GrGLenum status; | 1270 GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, |
| 1279 GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); | 1271 GR_GL_DEPTH_ATTACHMENT, |
| 1280 if (status != GR_GL_FRAMEBUFFER_COMPLETE) { | 1272 GR_GL_RENDERBUFFER, 0)); |
| 1273 } |
| 1274 GrGLenum status; |
| 1275 GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER
)); |
| 1276 if (status == GR_GL_FRAMEBUFFER_COMPLETE) { |
| 1277 firstWorkingStencilFormatIndex = i; |
| 1278 break; |
| 1279 } |
| 1281 GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, | 1280 GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, |
| 1282 GR_GL_STENCIL_ATTACHMENT, | 1281 GR_GL_STENCIL_ATTACHMENT, |
| 1283 GR_GL_RENDERBUFFER, 0)); | 1282 GR_GL_RENDERBUFFER, 0)); |
| 1284 if (sFmt.fPacked) { | 1283 if (sFmt.fPacked) { |
| 1285 GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, | 1284 GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, |
| 1286 GR_GL_DEPTH_ATTACHMENT, | 1285 GR_GL_DEPTH_ATTACHMENT, |
| 1287 GR_GL_RENDERBUFFER, 0)); | 1286 GR_GL_RENDERBUFFER, 0)); |
| 1288 } | 1287 } |
| 1289 } else { | |
| 1290 fConfigTable[config].fStencilFormatIndex = i; | |
| 1291 break; | |
| 1292 } | 1288 } |
| 1293 } | 1289 } |
| 1294 sbRBID = 0; | 1290 GL_CALL(DeleteRenderbuffers(1, &sbRBID)); |
| 1295 } | 1291 } |
| 1296 GL_CALL(DeleteTextures(1, &colorID)); | 1292 GL_CALL(DeleteTextures(1, &colorID)); |
| 1297 GL_CALL(DeleteRenderbuffers(1, &sbRBID)); | |
| 1298 GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, 0)); | 1293 GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, 0)); |
| 1299 GL_CALL(DeleteFramebuffers(1, &fb)); | 1294 GL_CALL(DeleteFramebuffers(1, &fb)); |
| 1295 fGLContext->caps()->setStencilFormatIndexForConfig(config, firstWorkingS
tencilFormatIndex); |
| 1300 } | 1296 } |
| 1301 SkASSERT(ConfigEntry::kUnknown_StencilIndex != fConfigTable[config].fStencil
FormatIndex); | 1297 return this->glCaps().getStencilFormatIndexForConfig(config); |
| 1302 return fConfigTable[config].fStencilFormatIndex; | |
| 1303 } | 1298 } |
| 1304 | 1299 |
| 1305 GrStencilAttachment* GrGLGpu::createStencilAttachmentForRenderTarget(const GrRen
derTarget* rt, | 1300 GrStencilAttachment* GrGLGpu::createStencilAttachmentForRenderTarget(const GrRen
derTarget* rt, |
| 1306 int width, | 1301 int width, |
| 1307 int height)
{ | 1302 int height)
{ |
| 1308 // All internally created RTs are also textures. We don't create | 1303 // All internally created RTs are also textures. We don't create |
| 1309 // SBs for a client's standalone RT (that is a RT that isn't also a texture)
. | 1304 // SBs for a client's standalone RT (that is a RT that isn't also a texture)
. |
| 1310 SkASSERT(rt->asTexture()); | 1305 SkASSERT(rt->asTexture()); |
| 1311 SkASSERT(width >= rt->width()); | 1306 SkASSERT(width >= rt->width()); |
| 1312 SkASSERT(height >= rt->height()); | 1307 SkASSERT(height >= rt->height()); |
| (...skipping 646 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1959 GrGLRenderTarget* tgt = static_cast<GrGLRenderTarget*>(surface->asRenderTarg
et()); | 1954 GrGLRenderTarget* tgt = static_cast<GrGLRenderTarget*>(surface->asRenderTarg
et()); |
| 1960 if (!tgt) { | 1955 if (!tgt) { |
| 1961 return false; | 1956 return false; |
| 1962 } | 1957 } |
| 1963 | 1958 |
| 1964 // OpenGL doesn't do sRGB <-> linear conversions when reading and writing pi
xels. | 1959 // OpenGL doesn't do sRGB <-> linear conversions when reading and writing pi
xels. |
| 1965 if (GrPixelConfigIsSRGB(surface->config()) != GrPixelConfigIsSRGB(config)) { | 1960 if (GrPixelConfigIsSRGB(surface->config()) != GrPixelConfigIsSRGB(config)) { |
| 1966 return false; | 1961 return false; |
| 1967 } | 1962 } |
| 1968 | 1963 |
| 1969 GrGLenum format = fConfigTable[config].fExternalFormat; | 1964 GrGLenum format = this->glCaps().configGLFormats(config).fExternalFormat; |
| 1970 GrGLenum type = fConfigTable[config].fExternalType; | 1965 GrGLenum type = this->glCaps().configGLFormats(config).fExternalType; |
| 1971 bool flipY = kBottomLeft_GrSurfaceOrigin == surface->origin(); | 1966 bool flipY = kBottomLeft_GrSurfaceOrigin == surface->origin(); |
| 1972 | 1967 |
| 1973 // resolve the render target if necessary | 1968 // resolve the render target if necessary |
| 1974 switch (tgt->getResolveType()) { | 1969 switch (tgt->getResolveType()) { |
| 1975 case GrGLRenderTarget::kCantResolve_ResolveType: | 1970 case GrGLRenderTarget::kCantResolve_ResolveType: |
| 1976 return false; | 1971 return false; |
| 1977 case GrGLRenderTarget::kAutoResolves_ResolveType: | 1972 case GrGLRenderTarget::kAutoResolves_ResolveType: |
| 1978 this->flushRenderTarget(tgt, &SkIRect::EmptyIRect()); | 1973 this->flushRenderTarget(tgt, &SkIRect::EmptyIRect()); |
| 1979 break; | 1974 break; |
| 1980 case GrGLRenderTarget::kCanResolve_ResolveType: | 1975 case GrGLRenderTarget::kCanResolve_ResolveType: |
| (...skipping 594 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2575 case GrPipelineBuilder::kBoth_DrawFace: | 2570 case GrPipelineBuilder::kBoth_DrawFace: |
| 2576 GL_CALL(Disable(GR_GL_CULL_FACE)); | 2571 GL_CALL(Disable(GR_GL_CULL_FACE)); |
| 2577 break; | 2572 break; |
| 2578 default: | 2573 default: |
| 2579 SkFAIL("Unknown draw face."); | 2574 SkFAIL("Unknown draw face."); |
| 2580 } | 2575 } |
| 2581 fHWDrawFace = face; | 2576 fHWDrawFace = face; |
| 2582 } | 2577 } |
| 2583 } | 2578 } |
| 2584 | 2579 |
| 2585 void GrGLGpu::generateConfigTable() { | |
| 2586 fConfigTable[kUnknown_GrPixelConfig].fBaseInternalFormat = 0; | |
| 2587 fConfigTable[kUnknown_GrPixelConfig].fSizedInternalFormat = 0; | |
| 2588 fConfigTable[kUnknown_GrPixelConfig].fExternalFormat = 0; | |
| 2589 fConfigTable[kUnknown_GrPixelConfig].fExternalType = 0; | |
| 2590 | |
| 2591 fConfigTable[kRGBA_8888_GrPixelConfig].fBaseInternalFormat = GR_GL_RGBA; | |
| 2592 fConfigTable[kRGBA_8888_GrPixelConfig].fSizedInternalFormat = GR_GL_RGBA8; | |
| 2593 fConfigTable[kRGBA_8888_GrPixelConfig].fExternalFormat = GR_GL_RGBA; | |
| 2594 fConfigTable[kRGBA_8888_GrPixelConfig].fExternalType = GR_GL_UNSIGNED_BYTE; | |
| 2595 | |
| 2596 if (this->glCaps().bgraIsInternalFormat()) { | |
| 2597 fConfigTable[kBGRA_8888_GrPixelConfig].fBaseInternalFormat = GR_GL_BGRA; | |
| 2598 fConfigTable[kBGRA_8888_GrPixelConfig].fSizedInternalFormat = GR_GL_BGRA
8; | |
| 2599 } else { | |
| 2600 fConfigTable[kBGRA_8888_GrPixelConfig].fBaseInternalFormat = GR_GL_RGBA; | |
| 2601 fConfigTable[kBGRA_8888_GrPixelConfig].fSizedInternalFormat = GR_GL_RGBA
8; | |
| 2602 } | |
| 2603 fConfigTable[kBGRA_8888_GrPixelConfig].fExternalFormat= GR_GL_BGRA; | |
| 2604 fConfigTable[kBGRA_8888_GrPixelConfig].fExternalType = GR_GL_UNSIGNED_BYTE; | |
| 2605 | |
| 2606 | |
| 2607 fConfigTable[kSRGBA_8888_GrPixelConfig].fBaseInternalFormat = GR_GL_SRGB_ALP
HA; | |
| 2608 fConfigTable[kSRGBA_8888_GrPixelConfig].fSizedInternalFormat = GR_GL_SRGB8_A
LPHA8; | |
| 2609 // GL does not do srgb<->rgb conversions when transferring between cpu and g
pu. Thus, the | |
| 2610 // external format is GL_RGBA. See below for note about ES2.0 and glTex[Sub]
Image. | |
| 2611 fConfigTable[kSRGBA_8888_GrPixelConfig].fExternalFormat = GR_GL_RGBA; | |
| 2612 fConfigTable[kSRGBA_8888_GrPixelConfig].fExternalType = GR_GL_UNSIGNED_BYTE; | |
| 2613 | |
| 2614 | |
| 2615 fConfigTable[kRGB_565_GrPixelConfig].fBaseInternalFormat = GR_GL_RGB; | |
| 2616 if (this->glCaps().ES2CompatibilitySupport()) { | |
| 2617 fConfigTable[kRGB_565_GrPixelConfig].fSizedInternalFormat = GR_GL_RGB565
; | |
| 2618 } else { | |
| 2619 fConfigTable[kRGB_565_GrPixelConfig].fSizedInternalFormat = GR_GL_RGB5; | |
| 2620 } | |
| 2621 fConfigTable[kRGB_565_GrPixelConfig].fExternalFormat = GR_GL_RGB; | |
| 2622 fConfigTable[kRGB_565_GrPixelConfig].fExternalType = GR_GL_UNSIGNED_SHORT_5_
6_5; | |
| 2623 | |
| 2624 fConfigTable[kRGBA_4444_GrPixelConfig].fBaseInternalFormat = GR_GL_RGBA; | |
| 2625 fConfigTable[kRGBA_4444_GrPixelConfig].fSizedInternalFormat = GR_GL_RGBA4; | |
| 2626 fConfigTable[kRGBA_4444_GrPixelConfig].fExternalFormat = GR_GL_RGBA; | |
| 2627 fConfigTable[kRGBA_4444_GrPixelConfig].fExternalType = GR_GL_UNSIGNED_SHORT_
4_4_4_4; | |
| 2628 | |
| 2629 | |
| 2630 if (this->glCaps().textureRedSupport()) { | |
| 2631 fConfigTable[kAlpha_8_GrPixelConfig].fBaseInternalFormat = GR_GL_RED; | |
| 2632 fConfigTable[kAlpha_8_GrPixelConfig].fSizedInternalFormat = GR_GL_R8; | |
| 2633 fConfigTable[kAlpha_8_GrPixelConfig].fExternalFormat = GR_GL_RED; | |
| 2634 } else { | |
| 2635 fConfigTable[kAlpha_8_GrPixelConfig].fBaseInternalFormat = GR_GL_ALPHA; | |
| 2636 fConfigTable[kAlpha_8_GrPixelConfig].fSizedInternalFormat = GR_GL_ALPHA8
; | |
| 2637 fConfigTable[kAlpha_8_GrPixelConfig].fExternalFormat = GR_GL_ALPHA; | |
| 2638 } | |
| 2639 fConfigTable[kAlpha_8_GrPixelConfig].fExternalType = GR_GL_UNSIGNED_BYTE; | |
| 2640 | |
| 2641 fConfigTable[kRGBA_float_GrPixelConfig].fBaseInternalFormat = GR_GL_RGBA; | |
| 2642 fConfigTable[kRGBA_float_GrPixelConfig].fSizedInternalFormat = GR_GL_RGBA32F
; | |
| 2643 fConfigTable[kRGBA_float_GrPixelConfig].fExternalFormat = GR_GL_RGBA; | |
| 2644 fConfigTable[kRGBA_float_GrPixelConfig].fExternalType = GR_GL_FLOAT; | |
| 2645 | |
| 2646 if (this->glCaps().textureRedSupport()) { | |
| 2647 fConfigTable[kAlpha_half_GrPixelConfig].fBaseInternalFormat = GR_GL_RED; | |
| 2648 fConfigTable[kAlpha_half_GrPixelConfig].fSizedInternalFormat = GR_GL_R16
F; | |
| 2649 fConfigTable[kAlpha_half_GrPixelConfig].fExternalFormat = GR_GL_RED; | |
| 2650 } else { | |
| 2651 fConfigTable[kAlpha_half_GrPixelConfig].fBaseInternalFormat = GR_GL_ALPH
A; | |
| 2652 fConfigTable[kAlpha_half_GrPixelConfig].fSizedInternalFormat = GR_GL_ALP
HA16F; | |
| 2653 fConfigTable[kAlpha_half_GrPixelConfig].fExternalFormat = GR_GL_ALPHA; | |
| 2654 } | |
| 2655 if (kGL_GrGLStandard == this->glStandard() || this->glVersion() >= GR_GL_VER
(3, 0)) { | |
| 2656 fConfigTable[kAlpha_half_GrPixelConfig].fExternalType = GR_GL_HALF_FLOAT
; | |
| 2657 } else { | |
| 2658 fConfigTable[kAlpha_half_GrPixelConfig].fExternalType = GR_GL_HALF_FLOAT
_OES; | |
| 2659 } | |
| 2660 | |
| 2661 fConfigTable[kRGBA_half_GrPixelConfig].fBaseInternalFormat = GR_GL_RGBA; | |
| 2662 fConfigTable[kRGBA_half_GrPixelConfig].fSizedInternalFormat = GR_GL_RGBA16F; | |
| 2663 fConfigTable[kRGBA_half_GrPixelConfig].fExternalFormat = GR_GL_RGBA; | |
| 2664 if (kGL_GrGLStandard == this->glStandard() || this->glVersion() >= GR_GL_VER
(3, 0)) { | |
| 2665 fConfigTable[kRGBA_half_GrPixelConfig].fExternalType = GR_GL_HALF_FLOAT; | |
| 2666 } else { | |
| 2667 fConfigTable[kRGBA_half_GrPixelConfig].fExternalType = GR_GL_HALF_FLOAT_
OES; | |
| 2668 } | |
| 2669 | |
| 2670 // No sized/unsized internal format distinction for compressed formats, no e
xternal format. | |
| 2671 | |
| 2672 fConfigTable[kIndex_8_GrPixelConfig].fBaseInternalFormat = GR_GL_PALETTE8_RG
BA8; | |
| 2673 fConfigTable[kIndex_8_GrPixelConfig].fSizedInternalFormat = GR_GL_PALETTE8_R
GBA8; | |
| 2674 fConfigTable[kIndex_8_GrPixelConfig].fExternalFormat = 0; | |
| 2675 fConfigTable[kIndex_8_GrPixelConfig].fExternalType = 0; | |
| 2676 | |
| 2677 switch(this->glCaps().latcAlias()) { | |
| 2678 case GrGLCaps::kLATC_LATCAlias: | |
| 2679 fConfigTable[kLATC_GrPixelConfig].fBaseInternalFormat = | |
| 2680 GR_GL_COMPRESSED_LUMINANCE_LATC1; | |
| 2681 fConfigTable[kLATC_GrPixelConfig].fSizedInternalFormat = | |
| 2682 GR_GL_COMPRESSED_LUMINANCE_LATC1; | |
| 2683 break; | |
| 2684 case GrGLCaps::kRGTC_LATCAlias: | |
| 2685 fConfigTable[kLATC_GrPixelConfig].fBaseInternalFormat = GR_GL_COMPRE
SSED_RED_RGTC1; | |
| 2686 fConfigTable[kLATC_GrPixelConfig].fSizedInternalFormat = GR_GL_COMPR
ESSED_RED_RGTC1; | |
| 2687 break; | |
| 2688 case GrGLCaps::k3DC_LATCAlias: | |
| 2689 fConfigTable[kLATC_GrPixelConfig].fBaseInternalFormat = GR_GL_COMPRE
SSED_3DC_X; | |
| 2690 fConfigTable[kLATC_GrPixelConfig].fSizedInternalFormat = GR_GL_COMPR
ESSED_3DC_X; | |
| 2691 break; | |
| 2692 } | |
| 2693 fConfigTable[kLATC_GrPixelConfig].fExternalFormat = 0; | |
| 2694 fConfigTable[kLATC_GrPixelConfig].fExternalType = 0; | |
| 2695 | |
| 2696 fConfigTable[kETC1_GrPixelConfig].fBaseInternalFormat = GR_GL_COMPRESSED_ETC
1_RGB8; | |
| 2697 fConfigTable[kETC1_GrPixelConfig].fSizedInternalFormat = GR_GL_COMPRESSED_ET
C1_RGB8; | |
| 2698 fConfigTable[kETC1_GrPixelConfig].fExternalFormat = 0; | |
| 2699 fConfigTable[kETC1_GrPixelConfig].fExternalType = 0; | |
| 2700 | |
| 2701 fConfigTable[kR11_EAC_GrPixelConfig].fBaseInternalFormat = GR_GL_COMPRESSED_
R11_EAC; | |
| 2702 fConfigTable[kR11_EAC_GrPixelConfig].fSizedInternalFormat = GR_GL_COMPRESSED
_R11_EAC; | |
| 2703 fConfigTable[kR11_EAC_GrPixelConfig].fExternalFormat = 0; | |
| 2704 fConfigTable[kR11_EAC_GrPixelConfig].fExternalType = 0; | |
| 2705 | |
| 2706 fConfigTable[kASTC_12x12_GrPixelConfig].fBaseInternalFormat = GR_GL_COMPRESS
ED_RGBA_ASTC_12x12; | |
| 2707 fConfigTable[kASTC_12x12_GrPixelConfig].fSizedInternalFormat = GR_GL_COMPRES
SED_RGBA_ASTC_12x12; | |
| 2708 fConfigTable[kASTC_12x12_GrPixelConfig].fExternalFormat = 0; | |
| 2709 fConfigTable[kASTC_12x12_GrPixelConfig].fExternalType = 0; | |
| 2710 | |
| 2711 // Bulk populate the texture internal/external formats here and then deal wi
th exceptions below. | |
| 2712 | |
| 2713 // ES 2.0 requires that the internal/external formats match. | |
| 2714 bool useSizedFormats = (kGL_GrGLStandard == this->glStandard() || | |
| 2715 this->glVersion() >= GR_GL_VER(3,0)); | |
| 2716 for (int i = 0; i < kGrPixelConfigCnt; ++i) { | |
| 2717 // Almost always we want to pass fExternalFormat as the <format> param t
o glTex[Sub]Image. | |
| 2718 fConfigTable[i].fExternalFormatForTexImage = fConfigTable[i].fExternalFo
rmat; | |
| 2719 fConfigTable[i].fInternalFormatTexImage = useSizedFormats ? | |
| 2720 fConfigTable[i].fSizedIn
ternalFormat : | |
| 2721 fConfigTable[i].fBaseInt
ernalFormat; | |
| 2722 } | |
| 2723 // OpenGL ES 2.0 + GL_EXT_sRGB allows GL_SRGB_ALPHA to be specified as the <
format> | |
| 2724 // param to Tex(Sub)Image. ES 2.0 requires the <internalFormat> and <format>
params to match. | |
| 2725 // Thus, on ES 2.0 we will use GL_SRGB_ALPHA as the <format> param. | |
| 2726 // On OpenGL and ES 3.0+ GL_SRGB_ALPHA does not work for the <format> param
to glTexImage. | |
| 2727 if (this->glStandard() == kGLES_GrGLStandard && this->glVersion() == GR_GL_V
ER(2,0)) { | |
| 2728 fConfigTable[kSRGBA_8888_GrPixelConfig].fExternalFormatForTexImage = GR_
GL_SRGB_ALPHA; | |
| 2729 } | |
| 2730 | |
| 2731 // If BGRA is supported as an internal format it must always be specified to
glTex[Sub]Image | |
| 2732 // as a base format. | |
| 2733 // GL_EXT_texture_format_BGRA8888: | |
| 2734 // This extension GL_BGRA as an unsized internal format. However, it is
written against ES | |
| 2735 // 2.0 and therefore doesn't define a value for GL_BGRA8 as ES 2.0 uses
unsized internal | |
| 2736 // formats. | |
| 2737 // GL_APPLE_texture_format_BGRA8888: | |
| 2738 // ES 2.0: the extension makes BGRA an external format but not an intern
al format. | |
| 2739 // ES 3.0: the extension explicitly states GL_BGRA8 is not a valid inter
nal format for | |
| 2740 // glTexImage (just for glTexStorage). | |
| 2741 if (useSizedFormats && this->glCaps().bgraIsInternalFormat()) { | |
| 2742 fConfigTable[kBGRA_8888_GrPixelConfig].fInternalFormatTexImage = GR_GL_B
GRA; | |
| 2743 } | |
| 2744 | |
| 2745 #ifdef SK_DEBUG | |
| 2746 // Make sure we initialized everything. | |
| 2747 ConfigEntry defaultEntry; | |
| 2748 for (int i = 0; i < kGrPixelConfigCnt; ++i) { | |
| 2749 SkASSERT(defaultEntry.fBaseInternalFormat != fConfigTable[i].fBaseIntern
alFormat); | |
| 2750 SkASSERT(defaultEntry.fSizedInternalFormat != fConfigTable[i].fSizedInte
rnalFormat); | |
| 2751 SkASSERT(defaultEntry.fExternalFormat != fConfigTable[i].fExternalFormat
); | |
| 2752 SkASSERT(defaultEntry.fExternalType != fConfigTable[i].fExternalType); | |
| 2753 } | |
| 2754 #endif | |
| 2755 } | |
| 2756 | |
| 2757 void GrGLGpu::setTextureUnit(int unit) { | 2580 void GrGLGpu::setTextureUnit(int unit) { |
| 2758 SkASSERT(unit >= 0 && unit < fHWBoundTextureUniqueIDs.count()); | 2581 SkASSERT(unit >= 0 && unit < fHWBoundTextureUniqueIDs.count()); |
| 2759 if (unit != fHWActiveTextureUnitIdx) { | 2582 if (unit != fHWActiveTextureUnitIdx) { |
| 2760 GL_CALL(ActiveTexture(GR_GL_TEXTURE0 + unit)); | 2583 GL_CALL(ActiveTexture(GR_GL_TEXTURE0 + unit)); |
| 2761 fHWActiveTextureUnitIdx = unit; | 2584 fHWActiveTextureUnitIdx = unit; |
| 2762 } | 2585 } |
| 2763 } | 2586 } |
| 2764 | 2587 |
| 2765 void GrGLGpu::setScratchTextureUnit() { | 2588 void GrGLGpu::setScratchTextureUnit() { |
| 2766 // Bind the last texture unit since it is the least likely to be used by GrG
LProgram. | 2589 // Bind the last texture unit since it is the least likely to be used by GrG
LProgram. |
| (...skipping 674 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3441 info->fID = 0; | 3264 info->fID = 0; |
| 3442 GL_CALL(GenTextures(1, &info->fID)); | 3265 GL_CALL(GenTextures(1, &info->fID)); |
| 3443 GL_CALL(ActiveTexture(GR_GL_TEXTURE0)); | 3266 GL_CALL(ActiveTexture(GR_GL_TEXTURE0)); |
| 3444 GL_CALL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, 1)); | 3267 GL_CALL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, 1)); |
| 3445 GL_CALL(BindTexture(info->fTarget, info->fID)); | 3268 GL_CALL(BindTexture(info->fTarget, info->fID)); |
| 3446 GL_CALL(TexParameteri(info->fTarget, GR_GL_TEXTURE_MAG_FILTER, GR_GL_NEAREST
)); | 3269 GL_CALL(TexParameteri(info->fTarget, GR_GL_TEXTURE_MAG_FILTER, GR_GL_NEAREST
)); |
| 3447 GL_CALL(TexParameteri(info->fTarget, GR_GL_TEXTURE_MIN_FILTER, GR_GL_NEAREST
)); | 3270 GL_CALL(TexParameteri(info->fTarget, GR_GL_TEXTURE_MIN_FILTER, GR_GL_NEAREST
)); |
| 3448 GL_CALL(TexParameteri(info->fTarget, GR_GL_TEXTURE_WRAP_S, GR_GL_CLAMP_TO_ED
GE)); | 3271 GL_CALL(TexParameteri(info->fTarget, GR_GL_TEXTURE_WRAP_S, GR_GL_CLAMP_TO_ED
GE)); |
| 3449 GL_CALL(TexParameteri(info->fTarget, GR_GL_TEXTURE_WRAP_T, GR_GL_CLAMP_TO_ED
GE)); | 3272 GL_CALL(TexParameteri(info->fTarget, GR_GL_TEXTURE_WRAP_T, GR_GL_CLAMP_TO_ED
GE)); |
| 3450 | 3273 |
| 3451 GrGLenum internalFormat = fConfigTable[config].fInternalFormatTexImage; | 3274 GrGLenum internalFormat = this->glCaps().configGLFormats(config).fInternalFo
rmatTexImage; |
| 3452 GrGLenum externalFormat = fConfigTable[config].fExternalFormatForTexImage; | 3275 GrGLenum externalFormat = this->glCaps().configGLFormats(config).fExternalFo
rmatForTexImage; |
| 3453 GrGLenum externalType = fConfigTable[config].fExternalType; | 3276 GrGLenum externalType = this->glCaps().configGLFormats(config).fExternalType
; |
| 3454 | 3277 |
| 3455 GL_CALL(TexImage2D(info->fTarget, 0, internalFormat, w, h, 0, externalFormat
, | 3278 GL_CALL(TexImage2D(info->fTarget, 0, internalFormat, w, h, 0, externalFormat
, |
| 3456 externalType, pixels)); | 3279 externalType, pixels)); |
| 3457 | 3280 |
| 3458 #ifdef SK_IGNORE_GL_TEXTURE_TARGET | 3281 #ifdef SK_IGNORE_GL_TEXTURE_TARGET |
| 3459 GrGLuint id = info->fID; | 3282 GrGLuint id = info->fID; |
| 3460 delete info; | 3283 delete info; |
| 3461 return id; | 3284 return id; |
| 3462 #else | 3285 #else |
| 3463 return reinterpret_cast<GrBackendObject>(info); | 3286 return reinterpret_cast<GrBackendObject>(info); |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3549 this->setVertexArrayID(gpu, 0); | 3372 this->setVertexArrayID(gpu, 0); |
| 3550 } | 3373 } |
| 3551 int attrCount = gpu->glCaps().maxVertexAttributes(); | 3374 int attrCount = gpu->glCaps().maxVertexAttributes(); |
| 3552 if (fDefaultVertexArrayAttribState.count() != attrCount) { | 3375 if (fDefaultVertexArrayAttribState.count() != attrCount) { |
| 3553 fDefaultVertexArrayAttribState.resize(attrCount); | 3376 fDefaultVertexArrayAttribState.resize(attrCount); |
| 3554 } | 3377 } |
| 3555 attribState = &fDefaultVertexArrayAttribState; | 3378 attribState = &fDefaultVertexArrayAttribState; |
| 3556 } | 3379 } |
| 3557 return attribState; | 3380 return attribState; |
| 3558 } | 3381 } |
| OLD | NEW |