void GrGLProgram::setColor(const GrDrawState& drawState, GrColor color, SharedGLState* sharedState) { const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader(); if (!drawState.hasColorVertexAttribute() || drawState.canIgnoreColorAttribute()) { switch (header.fColorInput) { case GrGLProgramDesc::kAttribute_ColorInput: SkASSERT(-1 != header.fColorAttributeIndex); if (sharedState->fConstAttribColor != color || sharedState->fConstAttribColorIndex != header.fColorAttributeIndex) { // OpenGL ES only supports the float varieties of glVertexAttrib GrGLfloat c[4]; GrColorToRGBAFloat(color, c); GL_CALL(VertexAttrib4fv(header.fColorAttributeIndex, c)); sharedState->fConstAttribColor = color; sharedState->fConstAttribColorIndex = header.fColorAttributeIndex; } break; case GrGLProgramDesc::kUniform_ColorInput: if (fColor != color && fBuilderOutput.fUniformHandles.fColorUni.isValid()) { // OpenGL ES doesn't support unsigned byte varieties of glUniform GrGLfloat c[4]; GrColorToRGBAFloat(color, c); fUniformManager->set4fv(fBuilderOutput.fUniformHandles.fColorUni, 1, c); fColor = color; } sharedState->fConstAttribColorIndex = -1; break; default: SkFAIL("Unexpected color type."); } } else { sharedState->fConstAttribColorIndex = -1; } }
void setup_vk_attachment_description(VkAttachmentDescription* attachment, const AttachmentDesc& desc, VkImageLayout layout) { attachment->flags = 0; attachment->format = desc.fFormat; SkAssertResult(GrSampleCountToVkSampleCount(desc.fSamples, &attachment->samples)); switch (layout) { case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: attachment->loadOp = desc.fLoadStoreOps.fLoadOp; attachment->storeOp = desc.fLoadStoreOps.fStoreOp; attachment->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; attachment->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; break; case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: attachment->loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; attachment->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; attachment->stencilLoadOp = desc.fLoadStoreOps.fLoadOp; attachment->stencilStoreOp = desc.fLoadStoreOps.fStoreOp; break; default: SkFAIL("Unexpected attachment layout"); } attachment->initialLayout = layout; attachment->finalLayout = layout; }
void GrOptDrawState::adjustFromBlendOpts() { switch (fBlendOptFlags) { case kNone_BlendOpt: case kSkipDraw_BlendOptFlag: break; case kCoverageAsAlpha_BlendOptFlag: fFlagBits |= kCoverageDrawing_StateBit; break; case kEmitCoverage_BlendOptFlag: fColor = 0xffffffff; fInputColorIsUsed = true; fColorStages.reset(); this->removeFixedFunctionVertexAttribs(0x1 << kColor_GrVertexAttribBinding); break; case kEmitTransBlack_BlendOptFlag: fColor = 0; fCoverage = 0xff; fInputColorIsUsed = true; fInputCoverageIsUsed = true; fColorStages.reset(); fCoverageStages.reset(); this->removeFixedFunctionVertexAttribs(0x1 << kColor_GrVertexAttribBinding | 0x1 << kCoverage_GrVertexAttribBinding); break; default: SkFAIL("Unknown BlendOptFlag"); } }
GrIndexBuffer* GrGpu::createInstancedIndexBuffer(const uint16_t* pattern, int patternSize, int reps, int vertCount, bool isDynamic) { size_t bufferSize = patternSize * reps * sizeof(uint16_t); GrGpu* me = const_cast<GrGpu*>(this); GrIndexBuffer* buffer = me->createIndexBuffer(bufferSize, isDynamic); if (buffer) { uint16_t* data = (uint16_t*) buffer->map(); bool useTempData = (NULL == data); if (useTempData) { data = SkNEW_ARRAY(uint16_t, reps * patternSize); } for (int i = 0; i < reps; ++i) { int baseIdx = i * patternSize; uint16_t baseVert = (uint16_t)(i * vertCount); for (int j = 0; j < patternSize; ++j) { data[baseIdx+j] = baseVert + pattern[j]; } } if (useTempData) { if (!buffer->updateData(data, bufferSize)) { SkFAIL("Can't get indices into buffer!"); } SkDELETE_ARRAY(data); } else { buffer->unmap(); } } return buffer; }
void GrGLConvolutionEffect::onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& processor) { const GrConvolutionEffect& conv = processor.cast<GrConvolutionEffect>(); GrTexture& texture = *conv.texture(0); // the code we generated was for a specific kernel radius SkASSERT(conv.radius() == fRadius); float imageIncrement[2] = { 0 }; float ySign = texture.origin() != kTopLeft_GrSurfaceOrigin ? 1.0f : -1.0f; switch (conv.direction()) { case Gr1DKernelEffect::kX_Direction: imageIncrement[0] = 1.0f / texture.width(); break; case Gr1DKernelEffect::kY_Direction: imageIncrement[1] = ySign / texture.height(); break; default: SkFAIL("Unknown filter direction."); } pdman.set2fv(fImageIncrementUni, 1, imageIncrement); if (conv.useBounds()) { const float* bounds = conv.bounds(); if (Gr1DKernelEffect::kY_Direction == conv.direction() && texture.origin() != kTopLeft_GrSurfaceOrigin) { pdman.set2f(fBoundsUni, 1.0f - bounds[1], 1.0f - bounds[0]); } else { pdman.set2f(fBoundsUni, bounds[0], bounds[1]); } } pdman.set1fv(fKernelUni, this->width(), conv.kernel()); }
void GrGLConvolutionEffect::onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& processor) { const GrConvolutionEffect& conv = processor.cast<GrConvolutionEffect>(); GrTexture& texture = *conv.texture(0); float imageIncrement[2] = { 0 }; float ySign = texture.origin() != kTopLeft_GrSurfaceOrigin ? 1.0f : -1.0f; switch (conv.direction()) { case Gr1DKernelEffect::kX_Direction: imageIncrement[0] = 1.0f / texture.width(); break; case Gr1DKernelEffect::kY_Direction: imageIncrement[1] = ySign / texture.height(); break; default: SkFAIL("Unknown filter direction."); } pdman.set2fv(fImageIncrementUni, 1, imageIncrement); if (conv.useBounds()) { const float* bounds = conv.bounds(); if (Gr1DKernelEffect::kY_Direction == conv.direction() && texture.origin() != kTopLeft_GrSurfaceOrigin) { pdman.set2f(fBoundsUni, 1.0f - bounds[1], 1.0f - bounds[0]); } else { pdman.set2f(fBoundsUni, bounds[0], bounds[1]); } } int width = Gr1DKernelEffect::WidthFromRadius(conv.radius()); int arrayCount = (width + 3) / 4; SkASSERT(4 * arrayCount >= width); pdman.set4fv(fKernelUni, arrayCount, conv.kernel()); }
void GrGLMorphologyEffect::setData(const GrGLProgramDataManager& pdman, const GrProcessor& proc) { const GrMorphologyEffect& m = proc.cast<GrMorphologyEffect>(); GrTexture& texture = *m.texture(0); // the code we generated was for a specific kernel radius, direction and bound usage SkASSERT(m.radius() == fRadius); SkASSERT(m.direction() == fDirection); SkASSERT(m.useRange() == fUseRange); float pixelSize = 0.0f; switch (fDirection) { case Gr1DKernelEffect::kX_Direction: pixelSize = 1.0f / texture.width(); break; case Gr1DKernelEffect::kY_Direction: pixelSize = 1.0f / texture.height(); break; default: SkFAIL("Unknown filter direction."); } pdman.set1f(fPixelSizeUni, pixelSize); if (fUseRange) { const float* range = m.range(); if (fDirection && texture.origin() == kBottomLeft_GrSurfaceOrigin) { pdman.set2f(fRangeUni, 1.0f - range[1], 1.0f - range[0]); } else { pdman.set2f(fRangeUni, range[0], range[1]); } } }
void GrProcessorTestFactory<GrGeometryProcessor>::VerifyFactoryCount() { if (kGPFactoryCount != GetFactories()->count()) { SkDebugf("\nExpected %d geometry processor factories, found %d.\n", kGPFactoryCount, GetFactories()->count()); SkFAIL("Wrong number of geometry processor factories!"); } }
void GrXPFactoryTestFactory::VerifyFactoryCount() { if (kXPFactoryCount != GetFactories()->count()) { SkDebugf("\nExpected %d xp factory factories, found %d.\n", kXPFactoryCount, GetFactories()->count()); SkFAIL("Wrong number of xp factory factories!"); } }
GrResourceIOProcessor::ImageStorageAccess::ImageStorageAccess(sk_sp<GrTexture> texture, GrIOType ioType, GrSLMemoryModel memoryModel, GrSLRestrict restrict, GrShaderFlags visibility) { SkASSERT(texture); fTexture.set(texture.release(), ioType); fMemoryModel = memoryModel; fRestrict = restrict; fVisibility = visibility; // We currently infer this from the config. However, we could allow the client to specify // a format that is different but compatible with the config. switch (fTexture.get()->config()) { case kRGBA_8888_GrPixelConfig: fFormat = GrImageStorageFormat::kRGBA8; break; case kRGBA_8888_sint_GrPixelConfig: fFormat = GrImageStorageFormat::kRGBA8i; break; case kRGBA_half_GrPixelConfig: fFormat = GrImageStorageFormat::kRGBA16f; break; case kRGBA_float_GrPixelConfig: fFormat = GrImageStorageFormat::kRGBA32f; break; default: SkFAIL("Config is not (yet) supported as image storage."); break; } }
void GrProcessorTestFactory<GrFragmentProcessor>::VerifyFactoryCount() { if (kFPFactoryCount != GetFactories()->count()) { SkDebugf("\nExpected %d fragment processor factories, found %d.\n", kFPFactoryCount, GetFactories()->count()); SkFAIL("Wrong number of fragment processor factories!"); } }
const GrIndexBuffer* GrGpu::getQuadIndexBuffer() const { if (NULL == fQuadIndexBuffer) { static const int SIZE = sizeof(uint16_t) * 6 * MAX_QUADS; GrGpu* me = const_cast<GrGpu*>(this); fQuadIndexBuffer = me->createIndexBuffer(SIZE, false); if (NULL != fQuadIndexBuffer) { uint16_t* indices = (uint16_t*)fQuadIndexBuffer->map(); if (NULL != indices) { fill_indices(indices, MAX_QUADS); fQuadIndexBuffer->unmap(); } else { indices = (uint16_t*)sk_malloc_throw(SIZE); fill_indices(indices, MAX_QUADS); if (!fQuadIndexBuffer->updateData(indices, SIZE)) { fQuadIndexBuffer->unref(); fQuadIndexBuffer = NULL; SkFAIL("Can't get indices into buffer!"); } sk_free(indices); } } } return fQuadIndexBuffer; }
void SkBaseDevice::drawTextBlob(const SkDraw& draw, const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint &paint) { SkPaint runPaint = paint; SkTextBlob::RunIterator it(blob); while (!it.done()) { size_t textLen = it.glyphCount() * sizeof(uint16_t); const SkPoint& offset = it.offset(); // applyFontToPaint() always overwrites the exact same attributes, // so it is safe to not re-seed the paint. it.applyFontToPaint(&runPaint); switch (it.positioning()) { case SkTextBlob::kDefault_Positioning: this->drawText(draw, it.glyphs(), textLen, x + offset.x(), y + offset.y(), runPaint); break; case SkTextBlob::kHorizontal_Positioning: this->drawPosText(draw, it.glyphs(), textLen, it.pos(), 1, SkPoint::Make(x, y + offset.y()), runPaint); break; case SkTextBlob::kFull_Positioning: this->drawPosText(draw, it.glyphs(), textLen, it.pos(), 2, SkPoint::Make(x, y), runPaint); break; default: SkFAIL("unhandled positioning mode"); } it.next(); } }
void GrGLPathTexGenProgramEffects::setPathTexGenState(GrGpuGL* gpu, const GrDrawEffect& drawEffect, int effectIdx) { uint32_t totalKey = fTransforms[effectIdx].fTransformKey; int texCoordIndex = fTransforms[effectIdx].fTexCoordIndex; int numTransforms = drawEffect.effect()->numTransforms(); for (int t = 0; t < numTransforms; ++t) { switch (get_matrix_type(totalKey, t)) { case kNoPersp_MatrixType: { const SkMatrix& transform = get_transform_matrix(drawEffect, t); gpu->enablePathTexGen(texCoordIndex++, GrGpuGL::kST_PathTexGenComponents, transform); break; } case kGeneral_MatrixType: { const SkMatrix& transform = get_transform_matrix(drawEffect, t); gpu->enablePathTexGen(texCoordIndex++, GrGpuGL::kSTR_PathTexGenComponents, transform); break; } default: SkFAIL("Unexpected matrixs type."); } } }
void GrGLVertexProgramEffects::emitTransforms(GrGLFullShaderBuilder* builder, const GrDrawEffect& drawEffect, TransformedCoordsArray* outCoords) { SkTArray<Transform, true>& transforms = fTransforms.push_back(); uint32_t totalKey = GenTransformKey(drawEffect); int numTransforms = drawEffect.effect()->numTransforms(); transforms.push_back_n(numTransforms); for (int t = 0; t < numTransforms; t++) { GrSLType varyingType = kVoid_GrSLType; const char* uniName; switch (get_matrix_type(totalKey, t)) { case kNoPersp_MatrixType: uniName = "StageMatrix"; varyingType = kVec2f_GrSLType; break; case kGeneral_MatrixType: uniName = "StageMatrix"; varyingType = kVec3f_GrSLType; break; default: SkFAIL("Unexpected key."); } SkString suffixedUniName; if (0 != t) { suffixedUniName.append(uniName); suffixedUniName.appendf("_%i", t); uniName = suffixedUniName.c_str(); } transforms[t].fHandle = builder->addUniform(GrGLShaderBuilder::kVertex_Visibility, kMat33f_GrSLType, uniName, &uniName); const char* varyingName = "MatrixCoord"; SkString suffixedVaryingName; if (0 != t) { suffixedVaryingName.append(varyingName); suffixedVaryingName.appendf("_%i", t); varyingName = suffixedVaryingName.c_str(); } const char* vsVaryingName; const char* fsVaryingName; builder->addVarying(varyingType, varyingName, &vsVaryingName, &fsVaryingName); const GrGLShaderVar& coords = kPosition_GrCoordSet == get_source_coords(totalKey, t) ? builder->positionAttribute() : builder->localCoordsAttribute(); // varying = matrix * coords (logically) SkASSERT(kVec2f_GrSLType == varyingType || kVec3f_GrSLType == varyingType); if (kVec2f_GrSLType == varyingType) { builder->vsCodeAppendf("\t%s = (%s * vec3(%s, 1)).xy;\n", vsVaryingName, uniName, coords.c_str()); } else { builder->vsCodeAppendf("\t%s = %s * vec3(%s, 1);\n", vsVaryingName, uniName, coords.c_str()); } SkNEW_APPEND_TO_TARRAY(outCoords, TransformedCoords, (SkString(fsVaryingName), varyingType)); } }
static void write_png(const png_bytep rgba, png_uint_32 width, png_uint_32 height, SkWStream& out) { png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); SkASSERT(png != nullptr); png_infop info_ptr = png_create_info_struct(png); SkASSERT(info_ptr != nullptr); if (setjmp(png_jmpbuf(png))) { SkFAIL("png encode error"); } png_set_IHDR(png, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_set_compression_level(png, 1); png_bytepp rows = (png_bytepp) sk_malloc_throw(height * sizeof(png_byte*)); png_bytep pixels = (png_bytep) sk_malloc_throw(width * height * 3); for (png_size_t y = 0; y < height; ++y) { const png_bytep src = rgba + y * width * 4; rows[y] = pixels + y * width * 3; // convert from RGBA to RGB for (png_size_t x = 0; x < width; ++x) { rows[y][x * 3] = src[x * 4]; rows[y][x * 3 + 1] = src[x * 4 + 1]; rows[y][x * 3 + 2] = src[x * 4 + 2]; } } png_set_filter(png, 0, PNG_NO_FILTERS); png_set_rows(png, info_ptr, &rows[0]); png_set_write_fn(png, &out, write_png_callback, NULL); png_write_png(png, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); png_destroy_write_struct(&png, NULL); sk_free(rows); }
static void update_degenerate_test(DegenerateTestData* data, const SkPoint& pt) { switch (data->fStage) { case DegenerateTestData::kInitial: data->fFirstPoint = pt; data->fStage = DegenerateTestData::kPoint; break; case DegenerateTestData::kPoint: if (pt.distanceToSqd(data->fFirstPoint) > kCloseSqd) { data->fLineNormal = pt - data->fFirstPoint; data->fLineNormal.normalize(); data->fLineNormal.setOrthog(data->fLineNormal); data->fLineC = -data->fLineNormal.dot(data->fFirstPoint); data->fStage = DegenerateTestData::kLine; } break; case DegenerateTestData::kLine: if (SkScalarAbs(data->fLineNormal.dot(pt) + data->fLineC) > kClose) { data->fStage = DegenerateTestData::kNonDegenerate; } case DegenerateTestData::kNonDegenerate: break; default: SkFAIL("Unexpected degenerate test stage."); } }
void drawTestCase(SkCanvas* canvas, const char* text, SkScalar y, const SkPaint& paint) { SkScalar widths[kMaxStringLength]; SkScalar posX[kMaxStringLength]; SkPoint pos[kMaxStringLength]; int length = SkToInt(strlen(text)); SkASSERT(length <= kMaxStringLength); paint.getTextWidths(text, length, widths); float originX; switch (paint.getTextAlign()) { case SkPaint::kRight_Align: originX = 1; break; case SkPaint::kCenter_Align: originX = 0.5f; break; case SkPaint::kLeft_Align: originX = 0; break; default: SkFAIL("Invalid paint origin"); return; } float x = kTextHeight; for (int i = 0; i < length; ++i) { posX[i] = x + originX * widths[i]; pos[i].set(posX[i], i ? pos[i - 1].y() + 3 : y + kTextHeight); x += widths[i]; } canvas->drawPosTextH(text, length, posX, y, paint); canvas->drawPosText(text, length, pos, paint); }
void GrGLMorphologyEffect::onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) { const GrMorphologyEffect& m = proc.cast<GrMorphologyEffect>(); GrTexture& texture = *m.texture(0); float pixelSize = 0.0f; switch (m.direction()) { case Gr1DKernelEffect::kX_Direction: pixelSize = 1.0f / texture.width(); break; case Gr1DKernelEffect::kY_Direction: pixelSize = 1.0f / texture.height(); break; default: SkFAIL("Unknown filter direction."); } pdman.set1f(fPixelSizeUni, pixelSize); if (m.useRange()) { const float* range = m.range(); if (m.direction() && texture.origin() == kBottomLeft_GrSurfaceOrigin) { pdman.set2f(fRangeUni, 1.0f - range[1], 1.0f - range[0]); } else { pdman.set2f(fRangeUni, range[0], range[1]); } } }
bool GrGLSLFragmentShaderBuilder::enableFeature(GLSLFeature feature) { switch (feature) { case kStandardDerivatives_GLSLFeature: { if (!fProgramBuilder->glslCaps()->shaderDerivativeSupport()) { return false; } const char* extension = fProgramBuilder->glslCaps()->shaderDerivativeExtensionString(); if (extension) { this->addFeature(1 << kStandardDerivatives_GLSLFeature, extension); } return true; } case kPixelLocalStorage_GLSLFeature: { if (fProgramBuilder->glslCaps()->pixelLocalStorageSize() <= 0) { return false; } this->addFeature(1 << kPixelLocalStorage_GLSLFeature, "GL_EXT_shader_pixel_local_storage"); return true; } default: SkFAIL("Unexpected GLSLFeature requested."); return false; } }
unsigned MaxComponentDifference(const SkBitmap& a, const SkBitmap& b) { if (a.info() != b.info()) { SkFAIL("Can't compare bitmaps of different shapes."); } unsigned max = 0; const SkAutoLockPixels lockA(a), lockB(b); if (a.info().colorType() == kRGB_565_SkColorType) { // 565 is special/annoying because its 3 components straddle 2 bytes. const uint16_t* aPixels = (const uint16_t*)a.getPixels(); const uint16_t* bPixels = (const uint16_t*)b.getPixels(); for (size_t i = 0; i < a.getSize() / 2; i++) { unsigned ar, ag, ab, br, bg, bb; unpack_565(aPixels[i], &ar, &ag, &ab); unpack_565(bPixels[i], &br, &bg, &bb); max = SkTMax(max, abs_diff(ar, br)); max = SkTMax(max, abs_diff(ag, bg)); max = SkTMax(max, abs_diff(ab, bb)); } } else { // Everything else we produce is byte aligned, so max component diff == max byte diff. const uint8_t* aBytes = (const uint8_t*)a.getPixels(); const uint8_t* bBytes = (const uint8_t*)b.getPixels(); for (size_t i = 0; i < a.getSize(); i++) { max = SkTMax(max, abs_diff(aBytes[i], bBytes[i])); } } return max; }
bool GrGLShaderBuilder::enablePrivateFeature(GLSLPrivateFeature feature) { switch (feature) { case kFragCoordConventions_GLSLPrivateFeature: if (!fGpu->glCaps().fragCoordConventionsSupport()) { return false; } if (fGpu->glslGeneration() < k150_GrGLSLGeneration) { this->addFSFeature(1 << kFragCoordConventions_GLSLPrivateFeature, "GL_ARB_fragment_coord_conventions"); } return true; case kEXTShaderFramebufferFetch_GLSLPrivateFeature: if (GrGLCaps::kEXT_FBFetchType != fGpu->glCaps().fbFetchType()) { return false; } this->addFSFeature(1 << kEXTShaderFramebufferFetch_GLSLPrivateFeature, "GL_EXT_shader_framebuffer_fetch"); return true; case kNVShaderFramebufferFetch_GLSLPrivateFeature: if (GrGLCaps::kNV_FBFetchType != fGpu->glCaps().fbFetchType()) { return false; } this->addFSFeature(1 << kNVShaderFramebufferFetch_GLSLPrivateFeature, "GL_NV_shader_framebuffer_fetch"); return true; default: SkFAIL("Unexpected GLSLPrivateFeature requested."); return false; } }
virtual void emitCode(GrGLFPBuilder* builder, const GrFragmentProcessor&, const char* outputColor, const char* inputColor, const TransformedCoordsArray& coords, const TextureSamplerArray& samplers) override { // Using highp for GLES here in order to avoid some precision issues on specific GPUs. GrGLShaderVar tmpVar("tmpColor", kVec4f_GrSLType, 0, kHigh_GrSLPrecision); SkString tmpDecl; tmpVar.appendDecl(builder->ctxInfo(), &tmpDecl); GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); fsBuilder->codeAppendf("%s;", tmpDecl.c_str()); fsBuilder->codeAppendf("%s = ", tmpVar.c_str()); fsBuilder->appendTextureLookup(samplers[0], coords[0].c_str(), coords[0].getType()); fsBuilder->codeAppend(";"); if (GrConfigConversionEffect::kNone_PMConversion == fPMConversion) { SkASSERT(fSwapRedAndBlue); fsBuilder->codeAppendf("%s = %s.bgra;", outputColor, tmpVar.c_str()); } else { const char* swiz = fSwapRedAndBlue ? "bgr" : "rgb"; switch (fPMConversion) { case GrConfigConversionEffect::kMulByAlpha_RoundUp_PMConversion: fsBuilder->codeAppendf( "%s = vec4(ceil(%s.%s * %s.a * 255.0) / 255.0, %s.a);", tmpVar.c_str(), tmpVar.c_str(), swiz, tmpVar.c_str(), tmpVar.c_str()); break; case GrConfigConversionEffect::kMulByAlpha_RoundDown_PMConversion: // Add a compensation(0.001) here to avoid the side effect of the floor operation. // In Intel GPUs, the integer value converted from floor(%s.r * 255.0) / 255.0 // is less than the integer value converted from %s.r by 1 when the %s.r is // converted from the integer value 2^n, such as 1, 2, 4, 8, etc. fsBuilder->codeAppendf( "%s = vec4(floor(%s.%s * %s.a * 255.0 + 0.001) / 255.0, %s.a);", tmpVar.c_str(), tmpVar.c_str(), swiz, tmpVar.c_str(), tmpVar.c_str()); break; case GrConfigConversionEffect::kDivByAlpha_RoundUp_PMConversion: fsBuilder->codeAppendf( "%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(ceil(%s.%s / %s.a * 255.0) / 255.0, %s.a);", tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), swiz, tmpVar.c_str(), tmpVar.c_str()); break; case GrConfigConversionEffect::kDivByAlpha_RoundDown_PMConversion: fsBuilder->codeAppendf( "%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(floor(%s.%s / %s.a * 255.0) / 255.0, %s.a);", tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), swiz, tmpVar.c_str(), tmpVar.c_str()); break; default: SkFAIL("Unknown conversion op."); break; } fsBuilder->codeAppendf("%s = %s;", outputColor, tmpVar.c_str()); } SkString modulate; GrGLSLMulVarBy4f(&modulate, outputColor, inputColor); fsBuilder->codeAppend(modulate.c_str()); }
void GLEllipticalRRectEffect::onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& effect) { const EllipticalRRectEffect& erre = effect.cast<EllipticalRRectEffect>(); const SkRRect& rrect = erre.getRRect(); // If we're using a scale factor to work around precision issues, choose the largest radius // as the scale factor. The inv radii need to be pre-adjusted by the scale factor. if (rrect != fPrevRRect) { SkRect rect = rrect.getBounds(); const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner); SkASSERT(r0.fX >= kRadiusMin); SkASSERT(r0.fY >= kRadiusMin); switch (erre.getRRect().getType()) { case SkRRect::kSimple_Type: rect.inset(r0.fX, r0.fY); if (fScaleUniform.isValid()) { if (r0.fX > r0.fY) { pdman.set2f(fInvRadiiSqdUniform, 1.f, (r0.fX * r0.fX) / (r0.fY * r0.fY)); pdman.set2f(fScaleUniform, r0.fX, 1.f / r0.fX); } else { pdman.set2f(fInvRadiiSqdUniform, (r0.fY * r0.fY) / (r0.fX * r0.fX), 1.f); pdman.set2f(fScaleUniform, r0.fY, 1.f / r0.fY); } } else { pdman.set2f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX), 1.f / (r0.fY * r0.fY)); } break; case SkRRect::kNinePatch_Type: { const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner); SkASSERT(r1.fX >= kRadiusMin); SkASSERT(r1.fY >= kRadiusMin); rect.fLeft += r0.fX; rect.fTop += r0.fY; rect.fRight -= r1.fX; rect.fBottom -= r1.fY; if (fScaleUniform.isValid()) { float scale = SkTMax(SkTMax(r0.fX, r0.fY), SkTMax(r1.fX, r1.fY)); float scaleSqd = scale * scale; pdman.set4f(fInvRadiiSqdUniform, scaleSqd / (r0.fX * r0.fX), scaleSqd / (r0.fY * r0.fY), scaleSqd / (r1.fX * r1.fX), scaleSqd / (r1.fY * r1.fY)); pdman.set2f(fScaleUniform, scale, 1.f / scale); } else { pdman.set4f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX), 1.f / (r0.fY * r0.fY), 1.f / (r1.fX * r1.fX), 1.f / (r1.fY * r1.fY)); } break; } default: SkFAIL("RRect should always be simple or nine-patch."); } pdman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); fPrevRRect = rrect; } }
static inline SkColor advance_color(SkColor old, ColorType ct, int step) { if (kAlternatingOpaqueAndTransparent_ColorType == ct) { ct = (step & 0x1) ? kChangingOpaque_ColorType : kChangingTransparent_ColorType ; } switch (ct) { case kConstantOpaque_ColorType: case kConstantTransparent_ColorType: return old; case kChangingOpaque_ColorType: return 0xFF000000 | (old + 0x00010307); case kChangingTransparent_ColorType: return (0x00FFFFFF & (old + 0x00010307)) | 0x80000000; case kAlternatingOpaqueAndTransparent_ColorType: SkFAIL("Can't get here"); } SkFAIL("Shouldn't reach here."); return 0; }
inline void pre_translate_transform_values(const float* xforms, GrPathRendering::PathTransformType type, int count, SkScalar x, SkScalar y, float* dst) { if (0 == x && 0 == y) { memcpy(dst, xforms, count * GrPathRendering::PathTransformSize(type) * sizeof(float)); return; } switch (type) { case GrPathRendering::kNone_PathTransformType: SkFAIL("Cannot pre-translate kNone_PathTransformType."); break; case GrPathRendering::kTranslateX_PathTransformType: SkASSERT(0 == y); for (int i = 0; i < count; i++) { dst[i] = xforms[i] + x; } break; case GrPathRendering::kTranslateY_PathTransformType: SkASSERT(0 == x); for (int i = 0; i < count; i++) { dst[i] = xforms[i] + y; } break; case GrPathRendering::kTranslate_PathTransformType: for (int i = 0; i < 2 * count; i += 2) { dst[i] = xforms[i] + x; dst[i + 1] = xforms[i + 1] + y; } break; case GrPathRendering::kAffine_PathTransformType: for (int i = 0; i < 6 * count; i += 6) { dst[i] = xforms[i]; dst[i + 1] = xforms[i + 1]; dst[i + 2] = xforms[i] * x + xforms[i + 1] * y + xforms[i + 2]; dst[i + 3] = xforms[i + 3]; dst[i + 4] = xforms[i + 4]; dst[i + 5] = xforms[i + 3] * x + xforms[i + 4] * y + xforms[i + 5]; } break; default: SkFAIL("Unknown transform type."); break; } }
const char* onGetName() override { switch (kClamp << 1 | kWide) { case 0: return "SkPMFloat_get_1x"; case 1: return "SkPMFloat_get_4x"; case 2: return "SkPMFloat_clamp_1x"; case 3: return "SkPMFloat_clamp_4x"; } SkFAIL("unreachable"); return "oh bother"; }
GrResourceKey::ResourceType GrResourceKey::GenerateResourceType() { static int32_t gNextType = 0; int32_t type = sk_atomic_inc(&gNextType); if (type >= (1 << 8 * sizeof(ResourceType))) { SkFAIL("Too many Resource Types"); } return static_cast<ResourceType>(type); }
GrScratchKey::ResourceType GrScratchKey::GenerateResourceType() { static int32_t gType = INHERITED::kInvalidDomain + 1; int32_t type = sk_atomic_inc(&gType); if (type > SK_MaxU16) { SkFAIL("Too many Resource Types"); } return static_cast<ResourceType>(type); }
GrUniqueKey::Domain GrUniqueKey::GenerateDomain() { static int32_t gDomain = INHERITED::kInvalidDomain + 1; int32_t domain = sk_atomic_inc(&gDomain); if (domain > SK_MaxU16) { SkFAIL("Too many GrUniqueKey Domains"); } return static_cast<Domain>(domain); }