| /* | |
| * 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"); | |
| } | |
| 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); | |
| } | |
| // This corresponds to GrGLSLProgramBuilder::emitAndInstallXferProc | |
| 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"); | |
| xp.addToKey(*caps.shaderCaps(), b); | |
| } | |
| 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"); | |
| } | |
| } | |
| } | |
| // This corresponds to GrGLSLProgramBuilder::emitAndInstallDstTexture | |
| static void gen_dstTexture_key(const GrCaps& caps, | |
| const GrPipeline& pipeline, | |
| skgpu::KeyBuilder* b) { | |
| const GrSurfaceProxyView& dstView = pipeline.dstProxyView(); | |
| if (dstView.proxy()) { | |
| uint32_t samplerKey = sampler_key(dstView.proxy()->backendFormat().textureType(), | |
| dstView.swizzle(), caps); | |
| b->add32(samplerKey); | |
| b->addBool(kTopLeft_GrSurfaceOrigin == dstView.origin(), "surfaceOrigin"); | |
| b->addBool(pipeline.usesDstInputAttachment(), "usesDstInputAttachment"); | |
| } | |
| } | |
| 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(); | |
| gen_dstTexture_key(caps, pipeline, b); | |
| // This corresponds to GrGLSLProgramBuilder::emitAndInstallFragProcs | |
| 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(); | |
| } |