1/* 2 * Copyright 2019 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "src/gpu/GrDirectContextPriv.h" 9 10#include "include/gpu/GrContextThreadSafeProxy.h" 11#include "include/gpu/GrDirectContext.h" 12#include "src/core/SkRuntimeEffectPriv.h" 13#include "src/gpu/GrContextThreadSafeProxyPriv.h" 14#include "src/gpu/GrDrawingManager.h" 15#include "src/gpu/GrGpu.h" 16#include "src/gpu/GrMemoryPool.h" 17#include "src/gpu/GrRecordingContextPriv.h" 18#include "src/gpu/GrTexture.h" 19#include "src/gpu/GrThreadSafePipelineBuilder.h" 20#include "src/gpu/GrTracing.h" 21#include "src/gpu/SkGr.h" 22#include "src/gpu/SurfaceContext.h" 23#include "src/gpu/SurfaceFillContext.h" 24#include "src/gpu/effects/GrSkSLFP.h" 25#include "src/gpu/effects/GrTextureEffect.h" 26#include "src/gpu/text/GrAtlasManager.h" 27#include "src/gpu/text/GrTextBlobCache.h" 28#include "src/image/SkImage_Base.h" 29#include "src/image/SkImage_Gpu.h" 30 31#define ASSERT_OWNED_PROXY(P) \ 32 SkASSERT(!(P) || !((P)->peekTexture()) || (P)->peekTexture()->getContext() == this->context()) 33#define ASSERT_SINGLE_OWNER GR_ASSERT_SINGLE_OWNER(this->context()->singleOwner()) 34#define RETURN_VALUE_IF_ABANDONED(value) if (this->context()->abandoned()) { return (value); } 35 36GrSemaphoresSubmitted GrDirectContextPriv::flushSurfaces( 37 SkSpan<GrSurfaceProxy*> proxies, 38 SkSurface::BackendSurfaceAccess access, 39 const GrFlushInfo& info, 40 const GrBackendSurfaceMutableState* newState) { 41 ASSERT_SINGLE_OWNER 42 GR_CREATE_TRACE_MARKER_CONTEXT("GrDirectContextPriv", "flushSurfaces", this->context()); 43 44 if (this->context()->abandoned()) { 45 if (info.fSubmittedProc) { 46 info.fSubmittedProc(info.fSubmittedContext, false); 47 } 48 if (info.fFinishedProc) { 49 info.fFinishedProc(info.fFinishedContext); 50 } 51 return GrSemaphoresSubmitted::kNo; 52 } 53 54#ifdef SK_DEBUG 55 for (GrSurfaceProxy* proxy : proxies) { 56 SkASSERT(proxy); 57 ASSERT_OWNED_PROXY(proxy); 58 } 59#endif 60 return this->context()->drawingManager()->flushSurfaces(proxies, access, info, newState); 61} 62 63void GrDirectContextPriv::createDDLTask(sk_sp<const SkDeferredDisplayList> ddl, 64 sk_sp<GrRenderTargetProxy> newDest, 65 SkIPoint offset) { 66 this->context()->drawingManager()->createDDLTask(std::move(ddl), std::move(newDest), offset); 67} 68 69bool GrDirectContextPriv::compile(const GrProgramDesc& desc, const GrProgramInfo& info) { 70 GrGpu* gpu = this->getGpu(); 71 if (!gpu) { 72 return false; 73 } 74 75 return gpu->compile(desc, info); 76} 77 78 79////////////////////////////////////////////////////////////////////////////// 80#if GR_TEST_UTILS 81 82void GrDirectContextPriv::dumpCacheStats(SkString* out) const { 83#if GR_CACHE_STATS 84 this->context()->fResourceCache->dumpStats(out); 85#endif 86} 87 88void GrDirectContextPriv::dumpCacheStatsKeyValuePairs(SkTArray<SkString>* keys, 89 SkTArray<double>* values) const { 90#if GR_CACHE_STATS 91 this->context()->fResourceCache->dumpStatsKeyValuePairs(keys, values); 92#endif 93} 94 95void GrDirectContextPriv::printCacheStats() const { 96 SkString out; 97 this->dumpCacheStats(&out); 98 SkDebugf("%s", out.c_str()); 99} 100 101///////////////////////////////////////////////// 102void GrDirectContextPriv::resetGpuStats() const { 103#if GR_GPU_STATS 104 this->context()->fGpu->stats()->reset(); 105#endif 106} 107 108void GrDirectContextPriv::dumpGpuStats(SkString* out) const { 109#if GR_GPU_STATS 110 this->context()->fGpu->stats()->dump(out); 111#ifdef SKIA_DFX_FOR_OHOS 112 this->context()->fResourceCache->dumpInfo(out); 113#endif 114 if (auto builder = this->context()->fGpu->pipelineBuilder()) { 115 builder->stats()->dump(out); 116 } 117#endif 118} 119 120void GrDirectContextPriv::dumpGpuStatsKeyValuePairs(SkTArray<SkString>* keys, 121 SkTArray<double>* values) const { 122#if GR_GPU_STATS 123 this->context()->fGpu->stats()->dumpKeyValuePairs(keys, values); 124 if (auto builder = this->context()->fGpu->pipelineBuilder()) { 125 builder->stats()->dumpKeyValuePairs(keys, values); 126 } 127#endif 128} 129 130void GrDirectContextPriv::printGpuStats() const { 131 SkString out; 132 this->dumpGpuStats(&out); 133 SkDebugf("%s", out.c_str()); 134} 135 136///////////////////////////////////////////////// 137void GrDirectContextPriv::resetContextStats() { 138#if GR_GPU_STATS 139 this->context()->stats()->reset(); 140#endif 141} 142 143void GrDirectContextPriv::dumpContextStats(SkString* out) const { 144#if GR_GPU_STATS 145 this->context()->stats()->dump(out); 146#endif 147} 148 149void GrDirectContextPriv::dumpContextStatsKeyValuePairs(SkTArray<SkString>* keys, 150 SkTArray<double>* values) const { 151#if GR_GPU_STATS 152 this->context()->stats()->dumpKeyValuePairs(keys, values); 153#endif 154} 155 156void GrDirectContextPriv::printContextStats() const { 157 SkString out; 158 this->dumpContextStats(&out); 159 SkDebugf("%s", out.c_str()); 160} 161 162///////////////////////////////////////////////// 163sk_sp<SkImage> GrDirectContextPriv::testingOnly_getFontAtlasImage(GrMaskFormat format, 164 unsigned int index) { 165 auto atlasManager = this->getAtlasManager(); 166 if (!atlasManager) { 167 return nullptr; 168 } 169 170 unsigned int numActiveProxies; 171 const GrSurfaceProxyView* views = atlasManager->getViews(format, &numActiveProxies); 172 if (index >= numActiveProxies || !views || !views[index].proxy()) { 173 return nullptr; 174 } 175 176 SkColorType colorType = GrColorTypeToSkColorType(GrMaskFormatToColorType(format)); 177 SkASSERT(views[index].proxy()->priv().isExact()); 178 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(this->context()), 179 kNeedNewImageUniqueID, 180 views[index], 181 SkColorInfo(colorType, kPremul_SkAlphaType, nullptr)); 182} 183 184void GrDirectContextPriv::testingOnly_flushAndRemoveOnFlushCallbackObject( 185 GrOnFlushCallbackObject* cb) { 186 this->context()->flushAndSubmit(); 187 this->context()->drawingManager()->testingOnly_removeOnFlushCallbackObject(cb); 188} 189#endif 190 191// Both of these effects aggressively round to the nearest exact (N / 255) floating point values. 192// This lets us find a round-trip preserving pair on some GPUs that do odd byte to float conversion. 193static std::unique_ptr<GrFragmentProcessor> make_premul_effect( 194 std::unique_ptr<GrFragmentProcessor> fp) { 195 if (!fp) { 196 return nullptr; 197 } 198 199 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"( 200 half4 main(half4 halfColor) { 201 float4 color = float4(halfColor); 202 color = floor(color * 255 + 0.5) / 255; 203 color.rgb = floor(color.rgb * color.a * 255 + 0.5) / 255; 204 return color; 205 } 206 )"); 207 208 fp = GrSkSLFP::Make(effect, "ToPremul", std::move(fp), GrSkSLFP::OptFlags::kNone); 209 return GrFragmentProcessor::HighPrecision(std::move(fp)); 210} 211 212static std::unique_ptr<GrFragmentProcessor> make_unpremul_effect( 213 std::unique_ptr<GrFragmentProcessor> fp) { 214 if (!fp) { 215 return nullptr; 216 } 217 218 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"( 219 half4 main(half4 halfColor) { 220 float4 color = float4(halfColor); 221 color = floor(color * 255 + 0.5) / 255; 222 color.rgb = color.a <= 0 ? half3(0) : floor(color.rgb / color.a * 255 + 0.5) / 255; 223 return color; 224 } 225 )"); 226 227 fp = GrSkSLFP::Make(effect, "ToUnpremul", std::move(fp), GrSkSLFP::OptFlags::kNone); 228 return GrFragmentProcessor::HighPrecision(std::move(fp)); 229} 230 231static bool test_for_preserving_PM_conversions(GrDirectContext* dContext) { 232 static constexpr int kSize = 256; 233 SkAutoTMalloc<uint32_t> data(kSize * kSize * 3); 234 uint32_t* srcData = data.get(); 235 236 // Fill with every possible premultiplied A, color channel value. There will be 256-y duplicate 237 // values in row y. We set r, g, and b to the same value since they are handled identically. 238 for (int y = 0; y < kSize; ++y) { 239 for (int x = 0; x < kSize; ++x) { 240 uint8_t* color = reinterpret_cast<uint8_t*>(&srcData[kSize*y + x]); 241 color[3] = y; 242 color[2] = std::min(x, y); 243 color[1] = std::min(x, y); 244 color[0] = std::min(x, y); 245 } 246 } 247 248 const SkImageInfo pmII = 249 SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType); 250 const SkImageInfo upmII = pmII.makeAlphaType(kUnpremul_SkAlphaType); 251 252 auto readSFC = dContext->priv().makeSFC(upmII, SkBackingFit::kExact); 253 auto tempSFC = dContext->priv().makeSFC(pmII, SkBackingFit::kExact); 254 if (!readSFC || !tempSFC) { 255 return false; 256 } 257 258 // This function is only ever called if we are in a GrDirectContext since we are calling read 259 // pixels here. Thus the pixel data will be uploaded immediately and we don't need to keep the 260 // pixel data alive in the proxy. Therefore the ReleaseProc is nullptr. 261 SkBitmap bitmap; 262 bitmap.installPixels(pmII, srcData, 4 * kSize); 263 bitmap.setImmutable(); 264 265 auto dataView = std::get<0>(GrMakeUncachedBitmapProxyView(dContext, bitmap)); 266 if (!dataView) { 267 return false; 268 } 269 270 uint32_t* firstRead = data.get() + kSize*kSize; 271 uint32_t* secondRead = data.get() + 2*kSize*kSize; 272 std::fill_n( firstRead, kSize*kSize, 0); 273 std::fill_n(secondRead, kSize*kSize, 0); 274 275 GrPixmap firstReadPM( upmII, firstRead, kSize*sizeof(uint32_t)); 276 GrPixmap secondReadPM(upmII, secondRead, kSize*sizeof(uint32_t)); 277 278 // We do a PM->UPM draw from dataTex to readTex and read the data. Then we do a UPM->PM draw 279 // from readTex to tempTex followed by a PM->UPM draw to readTex and finally read the data. 280 // We then verify that two reads produced the same values. 281 282 auto fp1 = make_unpremul_effect(GrTextureEffect::Make(std::move(dataView), bitmap.alphaType())); 283 readSFC->fillRectWithFP(SkIRect::MakeWH(kSize, kSize), std::move(fp1)); 284 if (!readSFC->readPixels(dContext, firstReadPM, {0, 0})) { 285 return false; 286 } 287 288 auto fp2 = make_premul_effect( 289 GrTextureEffect::Make(readSFC->readSurfaceView(), readSFC->colorInfo().alphaType())); 290 tempSFC->fillRectWithFP(SkIRect::MakeWH(kSize, kSize), std::move(fp2)); 291 292 auto fp3 = make_unpremul_effect( 293 GrTextureEffect::Make(tempSFC->readSurfaceView(), tempSFC->colorInfo().alphaType())); 294 readSFC->fillRectWithFP(SkIRect::MakeWH(kSize, kSize), std::move(fp3)); 295 296 if (!readSFC->readPixels(dContext, secondReadPM, {0, 0})) { 297 return false; 298 } 299 300 for (int y = 0; y < kSize; ++y) { 301 for (int x = 0; x <= y; ++x) { 302 if (firstRead[kSize*y + x] != secondRead[kSize*y + x]) { 303 return false; 304 } 305 } 306 } 307 308 return true; 309} 310 311bool GrDirectContextPriv::validPMUPMConversionExists() { 312 ASSERT_SINGLE_OWNER 313 314 auto dContext = this->context(); 315 316 if (!dContext->fDidTestPMConversions) { 317 dContext->fPMUPMConversionsRoundTrip = test_for_preserving_PM_conversions(dContext); 318 dContext->fDidTestPMConversions = true; 319 } 320 321 // The PM<->UPM tests fail or succeed together so we only need to check one. 322 return dContext->fPMUPMConversionsRoundTrip; 323} 324 325std::unique_ptr<GrFragmentProcessor> GrDirectContextPriv::createPMToUPMEffect( 326 std::unique_ptr<GrFragmentProcessor> fp) { 327 ASSERT_SINGLE_OWNER 328 // We should have already called this->priv().validPMUPMConversionExists() in this case 329 SkASSERT(this->context()->fDidTestPMConversions); 330 // ...and it should have succeeded 331 SkASSERT(this->validPMUPMConversionExists()); 332 333 return make_unpremul_effect(std::move(fp)); 334} 335 336std::unique_ptr<GrFragmentProcessor> GrDirectContextPriv::createUPMToPMEffect( 337 std::unique_ptr<GrFragmentProcessor> fp) { 338 ASSERT_SINGLE_OWNER 339 // We should have already called this->priv().validPMUPMConversionExists() in this case 340 SkASSERT(this->context()->fDidTestPMConversions); 341 // ...and it should have succeeded 342 SkASSERT(this->validPMUPMConversionExists()); 343 344 return make_premul_effect(std::move(fp)); 345} 346