158b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com/*
258b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com * Copyright 2012 Google Inc.
358b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com *
458b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com * Use of this source code is governed by a BSD-style license that can be
558b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com * found in the LICENSE file.
658b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com */
758b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com
858b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com#include "GrSWMaskHelper.h"
95c2fca040ec74617644554a46c39ab038afe2f1bkrajcevski
1058b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com#include "GrDrawState.h"
119528bdb0dccee915505bcf99cb10659f85e2604brobertphillips@google.com#include "GrDrawTargetCaps.h"
1258b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com#include "GrGpu.h"
1358b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com
145c2fca040ec74617644554a46c39ab038afe2f1bkrajcevski#include "SkData.h"
155f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com#include "SkStrokeRec.h"
1612b4e27ae1a29460e91a59f38122483e1faec697sugoi@google.com
1758b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com// TODO: try to remove this #include
1858b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com#include "GrContext.h"
1958b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com
2058b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.comnamespace {
215c2fca040ec74617644554a46c39ab038afe2f1bkrajcevski
2258b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com/*
2358b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com * Convert a boolean operation into a transfer mode code
2458b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com */
2558b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.comSkXfermode::Mode op_to_mode(SkRegion::Op op) {
2658b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com
2758b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com    static const SkXfermode::Mode modeMap[] = {
2858b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com        SkXfermode::kDstOut_Mode,   // kDifference_Op
298d3cd7a170c810e3816bf00220cbef51e7b16795reed@google.com        SkXfermode::kModulate_Mode, // kIntersect_Op
3058b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com        SkXfermode::kSrcOver_Mode,  // kUnion_Op
3158b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com        SkXfermode::kXor_Mode,      // kXOR_Op
3258b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com        SkXfermode::kClear_Mode,    // kReverseDifference_Op
3358b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com        SkXfermode::kSrc_Mode,      // kReplace_Op
3458b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com    };
3558b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com
3658b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com    return modeMap[op];
3758b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com}
3858b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com
3925a67bcb7ac70d3077e91126c4b8924a53557a38krajcevskistatic inline GrPixelConfig fmt_to_config(SkTextureCompressor::Format fmt) {
4025a67bcb7ac70d3077e91126c4b8924a53557a38krajcevski
4195b1b3d82d227141647777d83324aa570b530096krajcevski    GrPixelConfig config;
4295b1b3d82d227141647777d83324aa570b530096krajcevski    switch (fmt) {
4395b1b3d82d227141647777d83324aa570b530096krajcevski        case SkTextureCompressor::kLATC_Format:
4495b1b3d82d227141647777d83324aa570b530096krajcevski            config = kLATC_GrPixelConfig;
4595b1b3d82d227141647777d83324aa570b530096krajcevski            break;
4695b1b3d82d227141647777d83324aa570b530096krajcevski
4795b1b3d82d227141647777d83324aa570b530096krajcevski        case SkTextureCompressor::kR11_EAC_Format:
4895b1b3d82d227141647777d83324aa570b530096krajcevski            config = kR11_EAC_GrPixelConfig;
4995b1b3d82d227141647777d83324aa570b530096krajcevski            break;
5095b1b3d82d227141647777d83324aa570b530096krajcevski
5195b1b3d82d227141647777d83324aa570b530096krajcevski        case SkTextureCompressor::kASTC_12x12_Format:
5295b1b3d82d227141647777d83324aa570b530096krajcevski            config = kASTC_12x12_GrPixelConfig;
5395b1b3d82d227141647777d83324aa570b530096krajcevski            break;
5495b1b3d82d227141647777d83324aa570b530096krajcevski
5595b1b3d82d227141647777d83324aa570b530096krajcevski        case SkTextureCompressor::kETC1_Format:
5695b1b3d82d227141647777d83324aa570b530096krajcevski            config = kETC1_GrPixelConfig;
5795b1b3d82d227141647777d83324aa570b530096krajcevski            break;
5895b1b3d82d227141647777d83324aa570b530096krajcevski
5995b1b3d82d227141647777d83324aa570b530096krajcevski        default:
6095b1b3d82d227141647777d83324aa570b530096krajcevski            SkDEBUGFAIL("No GrPixelConfig for compression format!");
6195b1b3d82d227141647777d83324aa570b530096krajcevski            // Best guess
6295b1b3d82d227141647777d83324aa570b530096krajcevski            config = kAlpha_8_GrPixelConfig;
6395b1b3d82d227141647777d83324aa570b530096krajcevski            break;
6495b1b3d82d227141647777d83324aa570b530096krajcevski    }
6595b1b3d82d227141647777d83324aa570b530096krajcevski
6695b1b3d82d227141647777d83324aa570b530096krajcevski    return config;
6725a67bcb7ac70d3077e91126c4b8924a53557a38krajcevski}
6825a67bcb7ac70d3077e91126c4b8924a53557a38krajcevski
69b3abe90145b988883c9882de1ac42da963adbf67krajcevskistatic bool choose_compressed_fmt(const GrDrawTargetCaps* caps,
70b3abe90145b988883c9882de1ac42da963adbf67krajcevski                                  SkTextureCompressor::Format *fmt) {
71b3abe90145b988883c9882de1ac42da963adbf67krajcevski    if (NULL == fmt) {
72b3abe90145b988883c9882de1ac42da963adbf67krajcevski        return false;
73b3abe90145b988883c9882de1ac42da963adbf67krajcevski    }
74b3abe90145b988883c9882de1ac42da963adbf67krajcevski
75b3abe90145b988883c9882de1ac42da963adbf67krajcevski    // We can't use scratch textures without the ability to update
76b3abe90145b988883c9882de1ac42da963adbf67krajcevski    // compressed textures...
77b3abe90145b988883c9882de1ac42da963adbf67krajcevski    if (!(caps->compressedTexSubImageSupport())) {
78b3abe90145b988883c9882de1ac42da963adbf67krajcevski        return false;
79b3abe90145b988883c9882de1ac42da963adbf67krajcevski    }
80b3abe90145b988883c9882de1ac42da963adbf67krajcevski
81b3abe90145b988883c9882de1ac42da963adbf67krajcevski    // Figure out what our preferred texture type is. If ASTC is available, that always
82b3abe90145b988883c9882de1ac42da963adbf67krajcevski    // gives the biggest win. Otherwise, in terms of compression speed and accuracy,
83b3abe90145b988883c9882de1ac42da963adbf67krajcevski    // LATC has a slight edge over R11 EAC.
84b3abe90145b988883c9882de1ac42da963adbf67krajcevski    if (caps->isConfigTexturable(kASTC_12x12_GrPixelConfig)) {
85b3abe90145b988883c9882de1ac42da963adbf67krajcevski        *fmt = SkTextureCompressor::kASTC_12x12_Format;
86b3abe90145b988883c9882de1ac42da963adbf67krajcevski        return true;
87b3abe90145b988883c9882de1ac42da963adbf67krajcevski    } else if (caps->isConfigTexturable(kLATC_GrPixelConfig)) {
88b3abe90145b988883c9882de1ac42da963adbf67krajcevski        *fmt = SkTextureCompressor::kLATC_Format;
89b3abe90145b988883c9882de1ac42da963adbf67krajcevski        return true;
90b3abe90145b988883c9882de1ac42da963adbf67krajcevski    } else if (caps->isConfigTexturable(kR11_EAC_GrPixelConfig)) {
91b3abe90145b988883c9882de1ac42da963adbf67krajcevski        *fmt = SkTextureCompressor::kR11_EAC_Format;
92b3abe90145b988883c9882de1ac42da963adbf67krajcevski        return true;
93b3abe90145b988883c9882de1ac42da963adbf67krajcevski    }
94b3abe90145b988883c9882de1ac42da963adbf67krajcevski
95b3abe90145b988883c9882de1ac42da963adbf67krajcevski    return false;
96b3abe90145b988883c9882de1ac42da963adbf67krajcevski}
97b3abe90145b988883c9882de1ac42da963adbf67krajcevski
9858b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com}
9958b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com
10058b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com/**
10158b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com * Draw a single rect element of the clip stack into the accumulation bitmap
10258b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com */
103fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.orgvoid GrSWMaskHelper::draw(const SkRect& rect, SkRegion::Op op,
104366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com                          bool antiAlias, uint8_t alpha) {
10558b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com    SkPaint paint;
10658b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com
10758b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com    SkXfermode* mode = SkXfermode::Create(op_to_mode(op));
10858b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com
10971614ac7c63fe60dfe971f861e2b2d6325dd0039krajcevski    SkASSERT(kNone_CompressionMode == fCompressionMode);
11071614ac7c63fe60dfe971f861e2b2d6325dd0039krajcevski
11158b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com    paint.setXfermode(mode);
11258b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com    paint.setAntiAlias(antiAlias);
113366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com    paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha));
11458b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com
115366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com    fDraw.drawRect(rect, paint);
11658b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com
11758b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com    SkSafeUnref(mode);
11858b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com}
11958b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com
12058b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com/**
12158b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com * Draw a single path element of the clip stack into the accumulation bitmap
12258b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com */
1235f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.comvoid GrSWMaskHelper::draw(const SkPath& path, const SkStrokeRec& stroke, SkRegion::Op op,
12412b4e27ae1a29460e91a59f38122483e1faec697sugoi@google.com                          bool antiAlias, uint8_t alpha) {
12558b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com
12658b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com    SkPaint paint;
1275f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    if (stroke.isHairlineStyle()) {
12858b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com        paint.setStyle(SkPaint::kStroke_Style);
12958b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com        paint.setStrokeWidth(SK_Scalar1);
13058b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com    } else {
1315f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com        if (stroke.isFillStyle()) {
13212b4e27ae1a29460e91a59f38122483e1faec697sugoi@google.com            paint.setStyle(SkPaint::kFill_Style);
13312b4e27ae1a29460e91a59f38122483e1faec697sugoi@google.com        } else {
13412b4e27ae1a29460e91a59f38122483e1faec697sugoi@google.com            paint.setStyle(SkPaint::kStroke_Style);
13512b4e27ae1a29460e91a59f38122483e1faec697sugoi@google.com            paint.setStrokeJoin(stroke.getJoin());
13612b4e27ae1a29460e91a59f38122483e1faec697sugoi@google.com            paint.setStrokeCap(stroke.getCap());
1375f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com            paint.setStrokeWidth(stroke.getWidth());
13858b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com        }
13958b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com    }
14058b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com    paint.setAntiAlias(antiAlias);
14158b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com
142b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    SkTBlitterAllocator allocator;
143b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    SkBlitter* blitter = NULL;
144b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    if (kBlitter_CompressionMode == fCompressionMode) {
14549f085dddff10473b6ebf832a974288300224e60bsalomon        SkASSERT(fCompressedBuffer.get());
146b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski        blitter = SkTextureCompressor::CreateBlitterForFormat(
147b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski            fBM.width(), fBM.height(), fCompressedBuffer.get(), &allocator, fCompressedFormat);
148b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    }
149b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski
150126f7f5244502c0cbf1e5fec1d2ad7a0f2eb6c34reed@google.com    if (SkRegion::kReplace_Op == op && 0xFF == alpha) {
151126f7f5244502c0cbf1e5fec1d2ad7a0f2eb6c34reed@google.com        SkASSERT(0xFF == paint.getAlpha());
152b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski        fDraw.drawPathCoverage(path, paint, blitter);
153126f7f5244502c0cbf1e5fec1d2ad7a0f2eb6c34reed@google.com    } else {
154126f7f5244502c0cbf1e5fec1d2ad7a0f2eb6c34reed@google.com        paint.setXfermodeMode(op_to_mode(op));
155126f7f5244502c0cbf1e5fec1d2ad7a0f2eb6c34reed@google.com        paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha));
156b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski        fDraw.drawPath(path, paint, blitter);
157126f7f5244502c0cbf1e5fec1d2ad7a0f2eb6c34reed@google.com    }
15858b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com}
15958b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com
160fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.orgbool GrSWMaskHelper::init(const SkIRect& resultBounds,
16171614ac7c63fe60dfe971f861e2b2d6325dd0039krajcevski                          const SkMatrix* matrix,
16271614ac7c63fe60dfe971f861e2b2d6325dd0039krajcevski                          bool allowCompression) {
16349f085dddff10473b6ebf832a974288300224e60bsalomon    if (matrix) {
164366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com        fMatrix = *matrix;
16558b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com    } else {
16658b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com        fMatrix.setIdentity();
16758b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com    }
16858b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com
169366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com    // Now translate so the bound's UL corner is at the origin
170366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com    fMatrix.postTranslate(-resultBounds.fLeft * SK_Scalar1,
171366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com                          -resultBounds.fTop * SK_Scalar1);
172fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org    SkIRect bounds = SkIRect::MakeWH(resultBounds.width(),
173366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com                                     resultBounds.height());
17425a67bcb7ac70d3077e91126c4b8924a53557a38krajcevski
17571614ac7c63fe60dfe971f861e2b2d6325dd0039krajcevski    if (allowCompression &&
17671614ac7c63fe60dfe971f861e2b2d6325dd0039krajcevski        fContext->getOptions().fDrawPathToCompressedTexture &&
1779c6d4d744a9e0375d0e7d7a7b19558f5259fc3c3krajcevski        choose_compressed_fmt(fContext->getGpu()->caps(), &fCompressedFormat)) {
178b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski        fCompressionMode = kCompress_CompressionMode;
179b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    }
18025a67bcb7ac70d3077e91126c4b8924a53557a38krajcevski
181b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    // Make sure that the width is a multiple of the desired block dimensions
182b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    // to allow for specialized SIMD instructions that compress multiple blocks at a time.
183b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    int cmpWidth = bounds.fRight;
184b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    int cmpHeight = bounds.fBottom;
185b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    if (kCompress_CompressionMode == fCompressionMode) {
186b3abe90145b988883c9882de1ac42da963adbf67krajcevski        int dimX, dimY;
187b3abe90145b988883c9882de1ac42da963adbf67krajcevski        SkTextureCompressor::GetBlockDimensions(fCompressedFormat, &dimX, &dimY);
188b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski        cmpWidth = dimX * ((cmpWidth + (dimX - 1)) / dimX);
189b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski        cmpHeight = dimY * ((cmpHeight + (dimY - 1)) / dimY);
190b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski
191b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski        // Can we create a blitter?
192b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski        if (SkTextureCompressor::ExistsBlitterForFormat(fCompressedFormat)) {
193b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski            int cmpSz = SkTextureCompressor::GetCompressedDataSize(
194b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski                fCompressedFormat, cmpWidth, cmpHeight);
195b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski
196b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski            SkASSERT(cmpSz > 0);
197b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski            SkASSERT(NULL == fCompressedBuffer.get());
198b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski            fCompressedBuffer.reset(cmpSz);
199b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski            fCompressionMode = kBlitter_CompressionMode;
200b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski        }
201b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    }
202b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski
203b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    // If we don't have a custom blitter, then we either need a bitmap to compress
204b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    // from or a bitmap that we're going to use as a texture. In any case, we should
205b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    // allocate the pixels for a bitmap
206b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    const SkImageInfo bmImageInfo = SkImageInfo::MakeA8(cmpWidth, cmpHeight);
207b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    if (kBlitter_CompressionMode != fCompressionMode) {
208848250415eddc54075f7eb8795e8db79e749c6abreed        if (!fBM.tryAllocPixels(bmImageInfo)) {
209b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski            return false;
210b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski        }
21158b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com
212b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski        sk_bzero(fBM.getPixels(), fBM.getSafeSize());
213b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    } else {
214b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski        // Otherwise, we just need to remember how big the buffer is...
215b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski        fBM.setInfo(bmImageInfo);
21658b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com    }
217b577c55a13850b8f4739e14b10d426a3ec6b05d0krajcevski
21858b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com    sk_bzero(&fDraw, sizeof(fDraw));
219b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski
22058b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com    fRasterClip.setRect(bounds);
22158b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com    fDraw.fRC    = &fRasterClip;
22258b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com    fDraw.fClip  = &fRasterClip.bwRgn();
22358b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com    fDraw.fMatrix = &fMatrix;
22458b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com    fDraw.fBitmap = &fBM;
22558b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com    return true;
22658b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com}
22758b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com
22858b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com/**
229366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com * Get a texture (from the texture cache) of the correct size & format.
230366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com * Return true on success; false on failure.
23158b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com */
232366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.combool GrSWMaskHelper::getTexture(GrAutoScratchTexture* texture) {
23358b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com    GrTextureDesc desc;
23458b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com    desc.fWidth = fBM.width();
23558b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com    desc.fHeight = fBM.height();
236b3abe90145b988883c9882de1ac42da963adbf67krajcevski    desc.fConfig = kAlpha_8_GrPixelConfig;
237fb4f5cb39e31b8544b526074683a65bb716b7acfkrajcevski
238b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    if (kNone_CompressionMode != fCompressionMode) {
239b577c55a13850b8f4739e14b10d426a3ec6b05d0krajcevski
24025a67bcb7ac70d3077e91126c4b8924a53557a38krajcevski#ifdef SK_DEBUG
241b3abe90145b988883c9882de1ac42da963adbf67krajcevski        int dimX, dimY;
242b3abe90145b988883c9882de1ac42da963adbf67krajcevski        SkTextureCompressor::GetBlockDimensions(fCompressedFormat, &dimX, &dimY);
243b3abe90145b988883c9882de1ac42da963adbf67krajcevski        SkASSERT((desc.fWidth % dimX) == 0);
244b3abe90145b988883c9882de1ac42da963adbf67krajcevski        SkASSERT((desc.fHeight % dimY) == 0);
24525a67bcb7ac70d3077e91126c4b8924a53557a38krajcevski#endif
24625a67bcb7ac70d3077e91126c4b8924a53557a38krajcevski
247b3abe90145b988883c9882de1ac42da963adbf67krajcevski        desc.fConfig = fmt_to_config(fCompressedFormat);
248b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski        SkASSERT(fContext->getGpu()->caps()->isConfigTexturable(desc.fConfig));
249fb4f5cb39e31b8544b526074683a65bb716b7acfkrajcevski    }
25058b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com
251366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com    texture->set(fContext, desc);
25249f085dddff10473b6ebf832a974288300224e60bsalomon    return SkToBool(texture->texture());
25358b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com}
25458b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com
255fb4f5cb39e31b8544b526074683a65bb716b7acfkrajcevskivoid GrSWMaskHelper::sendTextureData(GrTexture *texture, const GrTextureDesc& desc,
256fb4f5cb39e31b8544b526074683a65bb716b7acfkrajcevski                                     const void *data, int rowbytes) {
257fb4f5cb39e31b8544b526074683a65bb716b7acfkrajcevski    // If we aren't reusing scratch textures we don't need to flush before
258fb4f5cb39e31b8544b526074683a65bb716b7acfkrajcevski    // writing since no one else will be using 'texture'
259fb4f5cb39e31b8544b526074683a65bb716b7acfkrajcevski    bool reuseScratch = fContext->getGpu()->caps()->reuseScratchTextures();
2605c2fca040ec74617644554a46c39ab038afe2f1bkrajcevski
261fb4f5cb39e31b8544b526074683a65bb716b7acfkrajcevski    // Since we're uploading to it, and it's compressed, 'texture' shouldn't
262fb4f5cb39e31b8544b526074683a65bb716b7acfkrajcevski    // have a render target.
263fb4f5cb39e31b8544b526074683a65bb716b7acfkrajcevski    SkASSERT(NULL == texture->asRenderTarget());
264fb4f5cb39e31b8544b526074683a65bb716b7acfkrajcevski
265fb4f5cb39e31b8544b526074683a65bb716b7acfkrajcevski    texture->writePixels(0, 0, desc.fWidth, desc.fHeight,
266fb4f5cb39e31b8544b526074683a65bb716b7acfkrajcevski                         desc.fConfig, data, rowbytes,
267fb4f5cb39e31b8544b526074683a65bb716b7acfkrajcevski                         reuseScratch ? 0 : GrContext::kDontFlush_PixelOpsFlag);
2685c2fca040ec74617644554a46c39ab038afe2f1bkrajcevski}
2695c2fca040ec74617644554a46c39ab038afe2f1bkrajcevski
270b577c55a13850b8f4739e14b10d426a3ec6b05d0krajcevskivoid GrSWMaskHelper::compressTextureData(GrTexture *texture, const GrTextureDesc& desc) {
271b577c55a13850b8f4739e14b10d426a3ec6b05d0krajcevski
272b577c55a13850b8f4739e14b10d426a3ec6b05d0krajcevski    SkASSERT(GrPixelConfigIsCompressed(desc.fConfig));
273b3abe90145b988883c9882de1ac42da963adbf67krajcevski    SkASSERT(fmt_to_config(fCompressedFormat) == desc.fConfig);
274b577c55a13850b8f4739e14b10d426a3ec6b05d0krajcevski
275b3abe90145b988883c9882de1ac42da963adbf67krajcevski    SkAutoDataUnref cmpData(SkTextureCompressor::CompressBitmapToFormat(fBM, fCompressedFormat));
27649f085dddff10473b6ebf832a974288300224e60bsalomon    SkASSERT(cmpData);
277b577c55a13850b8f4739e14b10d426a3ec6b05d0krajcevski
278b577c55a13850b8f4739e14b10d426a3ec6b05d0krajcevski    this->sendTextureData(texture, desc, cmpData->data(), 0);
279b577c55a13850b8f4739e14b10d426a3ec6b05d0krajcevski}
280b577c55a13850b8f4739e14b10d426a3ec6b05d0krajcevski
28158b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com/**
28258b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com * Move the result of the software mask generation back to the gpu
28358b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com */
284d92cf2ebbfbb9d737ea4a551e64ffccb08376875robertphillips@google.comvoid GrSWMaskHelper::toTexture(GrTexture *texture) {
28558b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com    SkAutoLockPixels alp(fBM);
28658b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com
287fb4f5cb39e31b8544b526074683a65bb716b7acfkrajcevski    GrTextureDesc desc;
288fb4f5cb39e31b8544b526074683a65bb716b7acfkrajcevski    desc.fWidth = fBM.width();
289fb4f5cb39e31b8544b526074683a65bb716b7acfkrajcevski    desc.fHeight = fBM.height();
290fb4f5cb39e31b8544b526074683a65bb716b7acfkrajcevski    desc.fConfig = texture->config();
291fb4f5cb39e31b8544b526074683a65bb716b7acfkrajcevski
292fb4f5cb39e31b8544b526074683a65bb716b7acfkrajcevski    // First see if we should compress this texture before uploading.
293b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski    switch (fCompressionMode) {
294b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski        case kNone_CompressionMode:
295b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski            this->sendTextureData(texture, desc, fBM.getPixels(), fBM.rowBytes());
296b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski            break;
297b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski
298b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski        case kCompress_CompressionMode:
299b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski            this->compressTextureData(texture, desc);
300b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski            break;
301b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski
302b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski        case kBlitter_CompressionMode:
30349f085dddff10473b6ebf832a974288300224e60bsalomon            SkASSERT(fCompressedBuffer.get());
304b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski            this->sendTextureData(texture, desc, fCompressedBuffer.get(), 0);
305b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski            break;
306fb4f5cb39e31b8544b526074683a65bb716b7acfkrajcevski    }
30758b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com}
30858b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com
309366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com////////////////////////////////////////////////////////////////////////////////
310366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com/**
311fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com * Software rasterizes path to A8 mask (possibly using the context's matrix)
3125dfb67219a308edecafbe09eebb35c5e149db6e6robertphillips@google.com * and uploads the result to a scratch texture. Returns the resulting
3135dfb67219a308edecafbe09eebb35c5e149db6e6robertphillips@google.com * texture on success; NULL on failure.
314366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com */
3155dfb67219a308edecafbe09eebb35c5e149db6e6robertphillips@google.comGrTexture* GrSWMaskHelper::DrawPathMaskToTexture(GrContext* context,
3165dfb67219a308edecafbe09eebb35c5e149db6e6robertphillips@google.com                                                 const SkPath& path,
3175f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com                                                 const SkStrokeRec& stroke,
318fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org                                                 const SkIRect& resultBounds,
3195dfb67219a308edecafbe09eebb35c5e149db6e6robertphillips@google.com                                                 bool antiAlias,
320b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com                                                 SkMatrix* matrix) {
321366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com    GrSWMaskHelper helper(context);
322366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com
32384e922bfb3e7a03f6e35beb2f1e4f2657e7cd3e9reed@google.com    if (!helper.init(resultBounds, matrix)) {
3245dfb67219a308edecafbe09eebb35c5e149db6e6robertphillips@google.com        return NULL;
325366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com    }
326366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com
32712b4e27ae1a29460e91a59f38122483e1faec697sugoi@google.com    helper.draw(path, stroke, SkRegion::kReplace_Op, antiAlias, 0xFF);
328366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com
3295c2fca040ec74617644554a46c39ab038afe2f1bkrajcevski    GrAutoScratchTexture ast;
3305dfb67219a308edecafbe09eebb35c5e149db6e6robertphillips@google.com    if (!helper.getTexture(&ast)) {
3315dfb67219a308edecafbe09eebb35c5e149db6e6robertphillips@google.com        return NULL;
332366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com    }
333366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com
334d92cf2ebbfbb9d737ea4a551e64ffccb08376875robertphillips@google.com    helper.toTexture(ast.texture());
335366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com
3365dfb67219a308edecafbe09eebb35c5e149db6e6robertphillips@google.com    return ast.detach();
3375dfb67219a308edecafbe09eebb35c5e149db6e6robertphillips@google.com}
3385dfb67219a308edecafbe09eebb35c5e149db6e6robertphillips@google.com
3395dfb67219a308edecafbe09eebb35c5e149db6e6robertphillips@google.comvoid GrSWMaskHelper::DrawToTargetWithPathMask(GrTexture* texture,
3405dfb67219a308edecafbe09eebb35c5e149db6e6robertphillips@google.com                                              GrDrawTarget* target,
341fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org                                              const SkIRect& rect) {
3425dfb67219a308edecafbe09eebb35c5e149db6e6robertphillips@google.com    GrDrawState* drawState = target->drawState();
3435dfb67219a308edecafbe09eebb35c5e149db6e6robertphillips@google.com
344137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    GrDrawState::AutoViewMatrixRestore avmr;
345137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    if (!avmr.setIdentity(drawState)) {
346e3d3216fe17b6afb2e613271b5246a2766e12df6bsalomon@google.com        return;
347e3d3216fe17b6afb2e613271b5246a2766e12df6bsalomon@google.com    }
348eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com    GrDrawState::AutoRestoreEffects are(drawState);
3495dfb67219a308edecafbe09eebb35c5e149db6e6robertphillips@google.com
350fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org    SkRect dstRect = SkRect::MakeLTRB(SK_Scalar1 * rect.fLeft,
351fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org                                      SK_Scalar1 * rect.fTop,
352fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org                                      SK_Scalar1 * rect.fRight,
353fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org                                      SK_Scalar1 * rect.fBottom);
354c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com
355c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com    // We want to use device coords to compute the texture coordinates. We set our matrix to be
356c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com    // equal to the view matrix followed by a translation so that the top-left of the device bounds
357c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com    // maps to 0,0, and then a scaling matrix to normalized coords. We apply this matrix to the
358c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com    // vertex positions rather than local coords.
359c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com    SkMatrix maskMatrix;
360c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com    maskMatrix.setIDiv(texture->width(), texture->height());
361c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com    maskMatrix.preTranslate(SkIntToScalar(-rect.fLeft), SkIntToScalar(-rect.fTop));
362c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com    maskMatrix.preConcat(drawState->getViewMatrix());
363c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com
364b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    drawState->addCoverageProcessor(
365c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com                         GrSimpleTextureEffect::Create(texture,
366c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com                                                       maskMatrix,
367b86add1ad37776818e1f730359ec587c9fdbff5fhumper@google.com                                                       GrTextureParams::kNone_FilterMode,
36877af6805e5faea1e2a5c0220098aec9082f3a6e5bsalomon@google.com                                                       kPosition_GrCoordSet))->unref();
369c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com
370c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com    target->drawSimpleRect(dstRect);
371366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com}
372