OLD | NEW |
---|---|
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2011 Google Inc. | 3 * Copyright 2011 Google Inc. |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 #include "GrContext.h" | 9 #include "GrContext.h" |
10 | 10 |
(...skipping 17 matching lines...) Expand all Loading... | |
28 #include "GrSoftwarePathRenderer.h" | 28 #include "GrSoftwarePathRenderer.h" |
29 #include "GrStencilBuffer.h" | 29 #include "GrStencilBuffer.h" |
30 #include "GrStencilAndCoverTextContext.h" | 30 #include "GrStencilAndCoverTextContext.h" |
31 #include "GrStrokeInfo.h" | 31 #include "GrStrokeInfo.h" |
32 #include "GrSurfacePriv.h" | 32 #include "GrSurfacePriv.h" |
33 #include "GrTextStrike.h" | 33 #include "GrTextStrike.h" |
34 #include "GrTexturePriv.h" | 34 #include "GrTexturePriv.h" |
35 #include "GrTraceMarker.h" | 35 #include "GrTraceMarker.h" |
36 #include "GrTracing.h" | 36 #include "GrTracing.h" |
37 #include "SkDashPathPriv.h" | 37 #include "SkDashPathPriv.h" |
38 #include "SkConfig8888.h" | |
38 #include "SkGr.h" | 39 #include "SkGr.h" |
39 #include "SkRTConf.h" | 40 #include "SkRTConf.h" |
40 #include "SkRRect.h" | 41 #include "SkRRect.h" |
41 #include "SkStrokeRec.h" | 42 #include "SkStrokeRec.h" |
42 #include "SkTLazy.h" | 43 #include "SkTLazy.h" |
43 #include "SkTLS.h" | 44 #include "SkTLS.h" |
44 #include "SkTraceEvent.h" | 45 #include "SkTraceEvent.h" |
45 | 46 |
46 // It can be useful to set this to false to test whether a bug is caused by usin g the | 47 // It can be useful to set this to false to test whether a bug is caused by usin g the |
47 // InOrderDrawBuffer, to compare performance of using/not using InOrderDrawBuffe r, or to make | 48 // InOrderDrawBuffer, to compare performance of using/not using InOrderDrawBuffe r, or to make |
(...skipping 1189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1237 | 1238 |
1238 if (kDiscard_FlushBit & flagsBitfield) { | 1239 if (kDiscard_FlushBit & flagsBitfield) { |
1239 fDrawBuffer->reset(); | 1240 fDrawBuffer->reset(); |
1240 } else { | 1241 } else { |
1241 fDrawBuffer->flush(); | 1242 fDrawBuffer->flush(); |
1242 } | 1243 } |
1243 fResourceCache->purgeAsNeeded(); | 1244 fResourceCache->purgeAsNeeded(); |
1244 fFlushToReduceCacheSize = false; | 1245 fFlushToReduceCacheSize = false; |
1245 } | 1246 } |
1246 | 1247 |
1247 bool GrContext::writeTexturePixels(GrTexture* texture, | 1248 bool GrContext::writeSurfacePixels(GrSurface* surface, |
1248 int left, int top, int width, int height, | 1249 int left, int top, int width, int height, |
1249 GrPixelConfig config, const void* buffer, siz e_t rowBytes, | 1250 GrPixelConfig srcConfig, const void* buffer, size_t rowBytes, |
1250 uint32_t flags) { | 1251 uint32_t pixelOpsFlags) { |
1251 ASSERT_OWNED_RESOURCE(texture); | |
1252 | 1252 |
1253 if ((kUnpremul_PixelOpsFlag & flags) || !fGpu->canWriteTexturePixels(texture , config)) { | 1253 { |
1254 if (texture->asRenderTarget()) { | 1254 GrTexture* texture = NULL; |
1255 return this->writeRenderTargetPixels(texture->asRenderTarget(), | 1255 if (!(kUnpremul_PixelOpsFlag & pixelOpsFlags) && (texture = surface->asT exture()) && |
1256 left, top, width, height, | 1256 fGpu->canWriteTexturePixels(texture, srcConfig)) { |
1257 config, buffer, rowBytes, flags ); | 1257 |
1258 } else { | 1258 if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) && |
1259 return false; | 1259 surface->surfacePriv().hasPendingIO()) { |
1260 this->flush(); | |
1261 } | |
1262 return fGpu->writeTexturePixels(texture, left, top, width, height, | |
1263 srcConfig, buffer, rowBytes); | |
1264 // Don't need to check kFlushWrites_PixelOp here, we just did a dire ct write so the | |
1265 // upload is already flushed. | |
1260 } | 1266 } |
1261 } | 1267 } |
1262 | 1268 |
1263 if (!(kDontFlush_PixelOpsFlag & flags) && texture->surfacePriv().hasPendingI O()) { | 1269 // If we didn't do a direct texture write then we upload the pixels to a tex ture and draw. |
1270 GrRenderTarget* renderTarget = surface->asRenderTarget(); | |
1271 if (NULL == renderTarget) { | |
1272 return false; | |
1273 } | |
1274 | |
1275 // We ignore the preferred config unless it is a R/B swap of the src config. In that case | |
1276 // we will upload the original src data to a scratch texture but we will spo of it as the swapped | |
1277 // config. This scratch will then have R and B swapped. We correct for this by swapping again | |
1278 // when drawing the scratch to the dst using a conversion effect. | |
1279 bool swapRAndB = false; | |
1280 GrPixelConfig writeConfig = srcConfig; | |
1281 if (GrPixelConfigSwapRAndB(srcConfig) == | |
1282 fGpu->preferredWritePixelsConfig(srcConfig, renderTarget->config())) { | |
1283 writeConfig = GrPixelConfigSwapRAndB(srcConfig); | |
1284 swapRAndB = true; | |
1285 } | |
1286 | |
1287 GrTextureDesc desc; | |
1288 desc.fWidth = width; | |
1289 desc.fHeight = height; | |
1290 desc.fConfig = writeConfig; | |
1291 GrAutoScratchTexture ast(this, desc); | |
1292 GrTexture* texture = ast.texture(); | |
1293 if (NULL == texture) { | |
1294 return false; | |
1295 } | |
1296 | |
1297 SkAutoTUnref<const GrFragmentProcessor> fp; | |
1298 SkMatrix textureMatrix; | |
1299 textureMatrix.setIDiv(texture->width(), texture->height()); | |
1300 | |
1301 // allocate a tmp buffer and sw convert the pixels to premul | |
1302 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0); | |
1303 | |
1304 if (kUnpremul_PixelOpsFlag & pixelOpsFlags) { | |
1305 if (!GrPixelConfigIs8888(srcConfig)) { | |
1306 return false; | |
1307 } | |
1308 fp.reset(this->createUPMToPMEffect(texture, swapRAndB, textureMatrix)); | |
1309 // handle the unpremul step on the CPU if we couldn't create an effect t o do it. | |
1310 if (NULL == fp) { | |
robertphillips
2014/10/13 13:37:33
sw_convert_to_premul ? Not sure though it could be
bsalomon
2014/10/13 14:56:54
Done.
| |
1311 SkSrcPixelInfo srcPI; | |
1312 if (!GrPixelConfig2ColorType(srcConfig, &srcPI.fColorType)) { | |
1313 return false; | |
1314 } | |
1315 srcPI.fAlphaType = kUnpremul_SkAlphaType; | |
1316 srcPI.fPixels = buffer; | |
1317 srcPI.fRowBytes = rowBytes; | |
1318 | |
1319 tmpPixels.reset(width * height); | |
1320 | |
1321 SkDstPixelInfo dstPI; | |
1322 dstPI.fColorType = srcPI.fColorType; | |
1323 dstPI.fAlphaType = kPremul_SkAlphaType; | |
1324 dstPI.fPixels = tmpPixels.get(); | |
1325 dstPI.fRowBytes = 4 * width; | |
1326 | |
1327 if (!srcPI.convertPixelsTo(&dstPI, width, height)) { | |
1328 return false; | |
1329 } | |
1330 | |
1331 buffer = tmpPixels.get(); | |
1332 rowBytes = 4 * width; | |
1333 } | |
1334 } | |
1335 if (NULL == fp) { | |
1336 fp.reset(GrConfigConversionEffect::Create(texture, | |
1337 swapRAndB, | |
1338 GrConfigConversionEffect::kNon e_PMConversion, | |
1339 textureMatrix)); | |
1340 } | |
1341 | |
1342 // Even if the client told us not to flush, we still flush here. The client may have known that | |
1343 // writes to the original surface caused no data hazards, but they can't kno w that the scratch | |
1344 // we just got is safe. | |
1345 if (texture->surfacePriv().hasPendingIO()) { | |
1264 this->flush(); | 1346 this->flush(); |
1265 } | 1347 } |
1266 | 1348 if (!fGpu->writeTexturePixels(texture, 0, 0, width, height, |
1267 return fGpu->writeTexturePixels(texture, left, top, width, height, | 1349 writeConfig, buffer, rowBytes)) { |
1268 config, buffer, rowBytes); | |
1269 | |
1270 // No need to check the kFlushWrites flag here since we issued the write dir ectly to fGpu. | |
1271 } | |
1272 | |
1273 bool GrContext::readTexturePixels(GrTexture* texture, | |
1274 int left, int top, int width, int height, | |
1275 GrPixelConfig config, void* buffer, size_t row Bytes, | |
1276 uint32_t flags) { | |
1277 ASSERT_OWNED_RESOURCE(texture); | |
1278 | |
1279 GrRenderTarget* target = texture->asRenderTarget(); | |
1280 if (target) { | |
1281 return this->readRenderTargetPixels(target, | |
1282 left, top, width, height, | |
1283 config, buffer, rowBytes, | |
1284 flags); | |
1285 } else { | |
1286 // TODO: make this more efficient for cases where we're reading the enti re | |
1287 // texture, i.e., use GetTexImage() instead | |
1288 | |
1289 // create scratch rendertarget and read from that | |
1290 GrAutoScratchTexture ast; | |
1291 GrTextureDesc desc; | |
1292 desc.fFlags = kRenderTarget_GrTextureFlagBit; | |
1293 desc.fWidth = width; | |
1294 desc.fHeight = height; | |
1295 desc.fConfig = config; | |
1296 desc.fOrigin = kTopLeft_GrSurfaceOrigin; | |
1297 ast.set(this, desc, kExact_ScratchTexMatch); | |
1298 GrTexture* dst = ast.texture(); | |
1299 if (dst && (target = dst->asRenderTarget())) { | |
1300 this->copySurface(target, texture, SkIRect::MakeXYWH(top, left, widt h, height), | |
1301 SkIPoint::Make(0,0)); | |
1302 return this->readRenderTargetPixels(target, | |
1303 left, top, width, height, | |
1304 config, buffer, rowBytes, | |
1305 flags); | |
1306 } | |
1307 | |
1308 return false; | 1350 return false; |
1309 } | 1351 } |
1352 | |
1353 SkMatrix matrix; | |
1354 matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top)); | |
1355 | |
1356 // This function can be called in the midst of drawing another object (e.g., when uploading a | |
1357 // SW-rasterized clip while issuing a draw). So we push the current geometry state before | |
1358 // drawing a rect to the render target. | |
1359 // The bracket ensures we pop the stack if we wind up flushing below. | |
1360 { | |
1361 GrDrawTarget* drawTarget = this->prepareToDraw(NULL, kYes_BufferedDraw, NULL, NULL); | |
1362 GrDrawTarget::AutoGeometryAndStatePush agasp(drawTarget, GrDrawTarget::k Reset_ASRInit, | |
1363 &matrix); | |
1364 GrDrawState* drawState = drawTarget->drawState(); | |
1365 drawState->addColorProcessor(fp); | |
1366 drawState->setRenderTarget(renderTarget); | |
1367 drawState->disableState(GrDrawState::kClip_StateBit); | |
1368 drawTarget->drawSimpleRect(SkRect::MakeWH(SkIntToScalar(width), SkIntToS calar(height))); | |
1369 } | |
1370 | |
1371 if (kFlushWrites_PixelOp & pixelOpsFlags) { | |
1372 this->flushSurfaceWrites(surface); | |
1373 } | |
1374 | |
1375 return true; | |
1310 } | 1376 } |
1311 | 1377 |
1312 #include "SkConfig8888.h" | |
1313 | |
1314 // toggles between RGBA and BGRA | 1378 // toggles between RGBA and BGRA |
1315 static SkColorType toggle_colortype32(SkColorType ct) { | 1379 static SkColorType toggle_colortype32(SkColorType ct) { |
1316 if (kRGBA_8888_SkColorType == ct) { | 1380 if (kRGBA_8888_SkColorType == ct) { |
1317 return kBGRA_8888_SkColorType; | 1381 return kBGRA_8888_SkColorType; |
1318 } else { | 1382 } else { |
1319 SkASSERT(kBGRA_8888_SkColorType == ct); | 1383 SkASSERT(kBGRA_8888_SkColorType == ct); |
1320 return kRGBA_8888_SkColorType; | 1384 return kRGBA_8888_SkColorType; |
1321 } | 1385 } |
1322 } | 1386 } |
1323 | 1387 |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1365 return false; | 1429 return false; |
1366 } | 1430 } |
1367 | 1431 |
1368 // If the src is a texture and we would have to do conversions after read pi xels, we instead | 1432 // If the src is a texture and we would have to do conversions after read pi xels, we instead |
1369 // do the conversions by drawing the src to a scratch texture. If we handle any of the | 1433 // do the conversions by drawing the src to a scratch texture. If we handle any of the |
1370 // conversions in the draw we set the corresponding bool to false so that we don't reapply it | 1434 // conversions in the draw we set the corresponding bool to false so that we don't reapply it |
1371 // on the read back pixels. | 1435 // on the read back pixels. |
1372 GrTexture* src = target->asTexture(); | 1436 GrTexture* src = target->asTexture(); |
1373 GrAutoScratchTexture ast; | 1437 GrAutoScratchTexture ast; |
1374 if (src && (swapRAndB || unpremul || flipY)) { | 1438 if (src && (swapRAndB || unpremul || flipY)) { |
1375 // Make the scratch a render target because we don't have a robust readT exturePixels as of | 1439 // Make the scratch a render so we can read its pixels. |
1376 // yet. It calls this function. | |
1377 GrTextureDesc desc; | 1440 GrTextureDesc desc; |
1378 desc.fFlags = kRenderTarget_GrTextureFlagBit; | 1441 desc.fFlags = kRenderTarget_GrTextureFlagBit; |
1379 desc.fWidth = width; | 1442 desc.fWidth = width; |
1380 desc.fHeight = height; | 1443 desc.fHeight = height; |
1381 desc.fConfig = readConfig; | 1444 desc.fConfig = readConfig; |
1382 desc.fOrigin = kTopLeft_GrSurfaceOrigin; | 1445 desc.fOrigin = kTopLeft_GrSurfaceOrigin; |
1383 | 1446 |
1384 // When a full read back is faster than a partial we could always make t he scratch exactly | 1447 // When a full read back is faster than a partial we could always make t he scratch exactly |
1385 // match the passed rect. However, if we see many different size rectang les we will trash | 1448 // match the passed rect. However, if we see many different size rectang les we will trash |
1386 // our texture cache and pay the cost of creating and destroying many te xtures. So, we only | 1449 // our texture cache and pay the cost of creating and destroying many te xtures. So, we only |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1501 if (NULL == target) { | 1564 if (NULL == target) { |
1502 return; | 1565 return; |
1503 } | 1566 } |
1504 target->copySurface(dst, src, srcRect, dstPoint); | 1567 target->copySurface(dst, src, srcRect, dstPoint); |
1505 | 1568 |
1506 if (kFlushWrites_PixelOp & pixelOpsFlags) { | 1569 if (kFlushWrites_PixelOp & pixelOpsFlags) { |
1507 this->flush(); | 1570 this->flush(); |
1508 } | 1571 } |
1509 } | 1572 } |
1510 | 1573 |
1511 bool GrContext::writeRenderTargetPixels(GrRenderTarget* renderTarget, | |
1512 int left, int top, int width, int height , | |
1513 GrPixelConfig srcConfig, | |
1514 const void* buffer, | |
1515 size_t rowBytes, | |
1516 uint32_t pixelOpsFlags) { | |
1517 ASSERT_OWNED_RESOURCE(renderTarget); | |
1518 | |
1519 if (NULL == renderTarget) { | |
1520 renderTarget = fRenderTarget.get(); | |
1521 if (NULL == renderTarget) { | |
1522 return false; | |
1523 } | |
1524 } | |
1525 | |
1526 // TODO: when underlying api has a direct way to do this we should use it (e .g. glDrawPixels on | |
1527 // desktop GL). | |
1528 | |
1529 // We will always call some form of writeTexturePixels and we will pass our flags on to it. | |
1530 // Thus, we don't perform a flush here since that call will do it (if the kN oFlush flag isn't | |
1531 // set.) | |
1532 | |
1533 // If the RT is also a texture and we don't have to premultiply then take th e texture path. | |
1534 // We expect to be at least as fast or faster since it doesn't use an interm ediate texture as | |
1535 // we do below. | |
1536 | |
1537 #if !defined(SK_BUILD_FOR_MAC) | |
1538 // At least some drivers on the Mac get confused when glTexImage2D is called on a texture | |
1539 // attached to an FBO. The FBO still sees the old image. TODO: determine wha t OS versions and/or | |
1540 // HW is affected. | |
1541 if (renderTarget->asTexture() && !(kUnpremul_PixelOpsFlag & pixelOpsFlags) & & | |
1542 fGpu->canWriteTexturePixels(renderTarget->asTexture(), srcConfig)) { | |
1543 return this->writeTexturePixels(renderTarget->asTexture(), | |
1544 left, top, width, height, | |
1545 srcConfig, buffer, rowBytes, pixelOpsFla gs); | |
1546 } | |
1547 #endif | |
1548 | |
1549 // We ignore the preferred config unless it is a R/B swap of the src config. In that case | |
1550 // we will upload the original src data to a scratch texture but we will spo of it as the swapped | |
1551 // config. This scratch will then have R and B swapped. We correct for this by swapping again | |
1552 // when drawing the scratch to the dst using a conversion effect. | |
1553 bool swapRAndB = false; | |
1554 GrPixelConfig writeConfig = srcConfig; | |
1555 if (GrPixelConfigSwapRAndB(srcConfig) == | |
1556 fGpu->preferredWritePixelsConfig(srcConfig, renderTarget->config())) { | |
1557 writeConfig = GrPixelConfigSwapRAndB(srcConfig); | |
1558 swapRAndB = true; | |
1559 } | |
1560 | |
1561 GrTextureDesc desc; | |
1562 desc.fWidth = width; | |
1563 desc.fHeight = height; | |
1564 desc.fConfig = writeConfig; | |
1565 GrAutoScratchTexture ast(this, desc); | |
1566 GrTexture* texture = ast.texture(); | |
1567 if (NULL == texture) { | |
1568 return false; | |
1569 } | |
1570 | |
1571 SkAutoTUnref<const GrFragmentProcessor> fp; | |
1572 SkMatrix textureMatrix; | |
1573 textureMatrix.setIDiv(texture->width(), texture->height()); | |
1574 | |
1575 // allocate a tmp buffer and sw convert the pixels to premul | |
1576 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0); | |
1577 | |
1578 if (kUnpremul_PixelOpsFlag & pixelOpsFlags) { | |
1579 if (!GrPixelConfigIs8888(srcConfig)) { | |
1580 return false; | |
1581 } | |
1582 fp.reset(this->createUPMToPMEffect(texture, swapRAndB, textureMatrix)); | |
1583 // handle the unpremul step on the CPU if we couldn't create an effect t o do it. | |
1584 if (NULL == fp) { | |
1585 SkSrcPixelInfo srcPI; | |
1586 if (!GrPixelConfig2ColorType(srcConfig, &srcPI.fColorType)) { | |
1587 return false; | |
1588 } | |
1589 srcPI.fAlphaType = kUnpremul_SkAlphaType; | |
1590 srcPI.fPixels = buffer; | |
1591 srcPI.fRowBytes = rowBytes; | |
1592 | |
1593 tmpPixels.reset(width * height); | |
1594 | |
1595 SkDstPixelInfo dstPI; | |
1596 dstPI.fColorType = srcPI.fColorType; | |
1597 dstPI.fAlphaType = kPremul_SkAlphaType; | |
1598 dstPI.fPixels = tmpPixels.get(); | |
1599 dstPI.fRowBytes = 4 * width; | |
1600 | |
1601 if (!srcPI.convertPixelsTo(&dstPI, width, height)) { | |
1602 return false; | |
1603 } | |
1604 | |
1605 buffer = tmpPixels.get(); | |
1606 rowBytes = 4 * width; | |
1607 } | |
1608 } | |
1609 if (NULL == fp) { | |
1610 fp.reset(GrConfigConversionEffect::Create(texture, | |
1611 swapRAndB, | |
1612 GrConfigConversionEffect::kNon e_PMConversion, | |
1613 textureMatrix)); | |
1614 } | |
1615 | |
1616 if (!this->writeTexturePixels(texture, | |
1617 0, 0, width, height, | |
1618 writeConfig, buffer, rowBytes, | |
1619 pixelOpsFlags & ~kUnpremul_PixelOpsFlag)) { | |
1620 return false; | |
1621 } | |
1622 | |
1623 SkMatrix matrix; | |
1624 matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top)); | |
1625 | |
1626 | |
1627 // This function can be called in the midst of drawing another object (e.g., when uploading a | |
1628 // SW-rasterized clip while issuing a draw). So we push the current geometry state before | |
1629 // drawing a rect to the render target. | |
1630 // The bracket ensures we pop the stack if we wind up flushing below. | |
1631 { | |
1632 GrDrawTarget* drawTarget = this->prepareToDraw(NULL, kYes_BufferedDraw, NULL, NULL); | |
1633 GrDrawTarget::AutoGeometryAndStatePush agasp(drawTarget, GrDrawTarget::k Reset_ASRInit, | |
1634 &matrix); | |
1635 GrDrawState* drawState = drawTarget->drawState(); | |
1636 drawState->addColorProcessor(fp); | |
1637 drawState->setRenderTarget(renderTarget); | |
1638 drawState->disableState(GrDrawState::kClip_StateBit); | |
1639 drawTarget->drawSimpleRect(SkRect::MakeWH(SkIntToScalar(width), SkIntToS calar(height))); | |
1640 } | |
1641 | |
1642 if (kFlushWrites_PixelOp & pixelOpsFlags) { | |
1643 this->flush(); | |
1644 } | |
1645 | |
1646 return true; | |
1647 } | |
1648 | |
1649 void GrContext::flushSurfaceWrites(GrSurface* surface) { | 1574 void GrContext::flushSurfaceWrites(GrSurface* surface) { |
1650 if (surface->surfacePriv().hasPendingWrite()) { | 1575 if (surface->surfacePriv().hasPendingWrite()) { |
1651 this->flush(); | 1576 this->flush(); |
1652 } | 1577 } |
1653 } | 1578 } |
1654 | 1579 |
1655 //////////////////////////////////////////////////////////////////////////////// | 1580 //////////////////////////////////////////////////////////////////////////////// |
1656 | 1581 |
1657 GrDrawTarget* GrContext::prepareToDraw(const GrPaint* paint, | 1582 GrDrawTarget* GrContext::prepareToDraw(const GrPaint* paint, |
1658 BufferedDraw buffered, | 1583 BufferedDraw buffered, |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1862 fResourceCache->printStats(); | 1787 fResourceCache->printStats(); |
1863 } | 1788 } |
1864 #endif | 1789 #endif |
1865 | 1790 |
1866 #if GR_GPU_STATS | 1791 #if GR_GPU_STATS |
1867 const GrContext::GPUStats* GrContext::gpuStats() const { | 1792 const GrContext::GPUStats* GrContext::gpuStats() const { |
1868 return fGpu->gpuStats(); | 1793 return fGpu->gpuStats(); |
1869 } | 1794 } |
1870 #endif | 1795 #endif |
1871 | 1796 |
OLD | NEW |