/* * Copyright 2016 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "src/gpu/ganesh/GrProgramDesc.h" #include "include/gpu/ganesh/GrBackendSurface.h" #include "include/private/base/SkAssert.h" #include "include/private/base/SkTo.h" #include "include/private/gpu/ganesh/GrTypesPriv.h" #include "src/gpu/KeyBuilder.h" #include "src/gpu/Swizzle.h" #include "src/gpu/ganesh/GrCaps.h" #include "src/gpu/ganesh/GrFragmentProcessor.h" #include "src/gpu/ganesh/GrGeometryProcessor.h" #include "src/gpu/ganesh/GrPipeline.h" #include "src/gpu/ganesh/GrProcessor.h" #include "src/gpu/ganesh/GrProgramInfo.h" #include "src/gpu/ganesh/GrSurfaceProxy.h" #include "src/gpu/ganesh/GrSurfaceProxyView.h" #include "src/gpu/ganesh/GrXferProcessor.h" #include "src/gpu/ganesh/effects/GrTextureEffect.h" enum GrSurfaceOrigin : int; // Currently we allow 8 bits for the class id static constexpr uint32_t kClassIDBits = 8; static constexpr uint32_t kSamplerOrImageTypeKeyBits = 4; static inline uint16_t texture_type_key(GrTextureType type) { int value = UINT16_MAX; switch (type) { case GrTextureType::k2D: value = 0; break; case GrTextureType::kExternal: value = 1; break; case GrTextureType::kRectangle: value = 2; break; default: SK_ABORT("Unexpected texture type"); value = 3; break; } SkASSERT((value & ((1 << kSamplerOrImageTypeKeyBits) - 1)) == value); return SkToU16(value); } static uint32_t sampler_key(GrTextureType textureType, const skgpu::Swizzle& swizzle, const GrCaps& caps) { int samplerTypeKey = texture_type_key(textureType); static_assert(2 == sizeof(swizzle.asKey())); uint16_t swizzleKey = swizzle.asKey(); return SkToU32(samplerTypeKey | swizzleKey << kSamplerOrImageTypeKeyBits); } static void add_geomproc_sampler_keys(skgpu::KeyBuilder* b, const GrGeometryProcessor& geomProc, const GrCaps& caps) { int numTextureSamplers = geomProc.numTextureSamplers(); b->add32(numTextureSamplers, "ppNumSamplers"); for (int i = 0; i < numTextureSamplers; ++i) { const GrGeometryProcessor::TextureSampler& sampler = geomProc.textureSampler(i); const GrBackendFormat& backendFormat = sampler.backendFormat(); uint32_t samplerKey = sampler_key(backendFormat.textureType(), sampler.swizzle(), caps); b->add32(samplerKey); caps.addExtraSamplerKey(b, sampler.samplerState(), backendFormat); } } /** * Functions which emit processor key info into the key builder. * For every effect, we include the effect's class ID (different for every GrProcessor subclass), * any information generated by the effect itself (addToKey), and some meta-information. * Shader code may be dependent on properties of the effect not placed in the key by the effect * (e.g. pixel format of textures used). */ static void gen_geomproc_key(const GrGeometryProcessor& geomProc, const GrCaps& caps, skgpu::KeyBuilder* b) { b->appendComment(geomProc.name()); b->addBits(kClassIDBits, geomProc.classID(), "geomProcClassID"); geomProc.addToKey(*caps.shaderCaps(), b); geomProc.getAttributeKey(b); add_geomproc_sampler_keys(b, geomProc, caps); } static void gen_xp_key(const GrXferProcessor& xp, const GrCaps& caps, const GrPipeline& pipeline, skgpu::KeyBuilder* b) { b->appendComment(xp.name()); b->addBits(kClassIDBits, xp.classID(), "xpClassID"); const GrSurfaceOrigin* originIfDstTexture = nullptr; GrSurfaceOrigin origin; const GrSurfaceProxyView& dstView = pipeline.dstProxyView(); if (dstView.proxy()) { origin = dstView.origin(); originIfDstTexture = &origin; uint32_t samplerKey = sampler_key(dstView.proxy()->backendFormat().textureType(), dstView.swizzle(), caps); b->add32(samplerKey); } xp.addToKey(*caps.shaderCaps(), b, originIfDstTexture, pipeline.dstSampleFlags() & GrDstSampleFlags::kAsInputAttachment); } static void gen_fp_key(const GrFragmentProcessor& fp, const GrCaps& caps, skgpu::KeyBuilder* b) { b->appendComment(fp.name()); b->addBits(kClassIDBits, fp.classID(), "fpClassID"); b->addBits(GrGeometryProcessor::kCoordTransformKeyBits, GrGeometryProcessor::ComputeCoordTransformsKey(fp), "fpTransforms"); if (auto* te = fp.asTextureEffect()) { const GrBackendFormat& backendFormat = te->view().proxy()->backendFormat(); uint32_t samplerKey = sampler_key(backendFormat.textureType(), te->view().swizzle(), caps); b->add32(samplerKey, "fpSamplerKey"); caps.addExtraSamplerKey(b, te->samplerState(), backendFormat); } fp.addToKey(*caps.shaderCaps(), b); b->add32(fp.numChildProcessors(), "fpNumChildren"); for (int i = 0; i < fp.numChildProcessors(); ++i) { if (auto child = fp.childProcessor(i)) { gen_fp_key(*child, caps, b); } else { // Fold in a sentinel value as the "class ID" for any null children b->appendComment("Null"); b->addBits(kClassIDBits, GrProcessor::ClassID::kNull_ClassID, "fpClassID"); } } } static void gen_key(skgpu::KeyBuilder* b, const GrProgramInfo& programInfo, const GrCaps& caps) { gen_geomproc_key(programInfo.geomProc(), caps, b); const GrPipeline& pipeline = programInfo.pipeline(); b->addBits(2, pipeline.numFragmentProcessors(), "numFPs"); b->addBits(1, pipeline.numColorFragmentProcessors(), "numColorFPs"); for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) { gen_fp_key(pipeline.getFragmentProcessor(i), caps, b); } gen_xp_key(pipeline.getXferProcessor(), caps, pipeline, b); b->addBits(16, pipeline.writeSwizzle().asKey(), "writeSwizzle"); b->addBool(pipeline.snapVerticesToPixelCenters(), "snapVertices"); // The base descriptor only stores whether or not the primitiveType is kPoints. Backend- // specific versions (e.g., Vulkan) require more detail b->addBool((programInfo.primitiveType() == GrPrimitiveType::kPoints), "isPoints"); // Put a clean break between the "common" data written by this function, and any backend data // appended later. The initial key length will just be this portion (rounded to 4 bytes). b->flush(); } void GrProgramDesc::Build(GrProgramDesc* desc, const GrProgramInfo& programInfo, const GrCaps& caps) { desc->reset(); skgpu::KeyBuilder b(desc->key()); gen_key(&b, programInfo, caps); desc->fInitialKeyLength = desc->keyLength(); } SkString GrProgramDesc::Describe(const GrProgramInfo& programInfo, const GrCaps& caps) { GrProgramDesc desc; skgpu::StringKeyBuilder b(desc.key()); gen_key(&b, programInfo, caps); b.flush(); return b.description(); }