static void test_clear(skiatest::Reporter* reporter, GrContext* context, GrTexture* rectangleTexture) { if (rectangleTexture->asRenderTarget()) { sk_sp<GrDrawContext> dc( context->drawContext(sk_ref_sp(rectangleTexture->asRenderTarget()), nullptr)); if (!dc) { ERRORF(reporter, "Could not get GrDrawContext for rectangle texture."); return; } // Clear the whole thing. GrColor color0 = GrColorPackRGBA(0xA, 0xB, 0xC, 0xD); dc->clear(nullptr, color0, false); int w = rectangleTexture->width(); int h = rectangleTexture->height(); int pixelCnt = w * h; SkAutoTMalloc<uint32_t> expectedPixels(pixelCnt); // The clear color is a GrColor, our readback is to kRGBA_8888, which may be different. uint32_t expectedColor0 = 0; uint8_t* expectedBytes0 = SkTCast<uint8_t*>(&expectedColor0); expectedBytes0[0] = GrColorUnpackR(color0); expectedBytes0[1] = GrColorUnpackG(color0); expectedBytes0[2] = GrColorUnpackB(color0); expectedBytes0[3] = GrColorUnpackA(color0); for (int i = 0; i < rectangleTexture->width() * rectangleTexture->height(); ++i) { expectedPixels.get()[i] = expectedColor0; } // Clear the the top to a different color. GrColor color1 = GrColorPackRGBA(0x1, 0x2, 0x3, 0x4); SkIRect rect = SkIRect::MakeWH(w, h/2); dc->clear(&rect, color1, false); uint32_t expectedColor1 = 0; uint8_t* expectedBytes1 = SkTCast<uint8_t*>(&expectedColor1); expectedBytes1[0] = GrColorUnpackR(color1); expectedBytes1[1] = GrColorUnpackG(color1); expectedBytes1[2] = GrColorUnpackB(color1); expectedBytes1[3] = GrColorUnpackA(color1); for (int y = 0; y < h/2; ++y) { for (int x = 0; x < w; ++x) { expectedPixels.get()[y * h + x] = expectedColor1; } } test_read_pixels(reporter, context, rectangleTexture, expectedPixels.get()); } }
bool does_full_buffer_contain_correct_color(GrColor* buffer, GrColor clearColor, GrPixelConfig config, int width, int height) { GrColor matchColor; if (kRGBA_8888_GrPixelConfig == config) { matchColor = clearColor; } else if (kBGRA_8888_GrPixelConfig) { // Hack to flip the R, B componets in the GrColor so that the comparrison will work below matchColor = GrColorPackRGBA(GrColorUnpackB(clearColor), GrColorUnpackG(clearColor), GrColorUnpackR(clearColor), GrColorUnpackA(clearColor)); } else { // currently only supporting rgba_8888 and bgra_8888 return false; } for (int j = 0; j < height; ++j) { for (int i = 0; i < width; ++i) { if (buffer[j * width + i] != matchColor) { return false; } } } return true; }
static void test_clear(skiatest::Reporter* reporter, GrSurfaceContext* rectContext) { if (GrRenderTargetContext* rtc = rectContext->asRenderTargetContext()) { // Clear the whole thing. GrColor color0 = GrColorPackRGBA(0xA, 0xB, 0xC, 0xD); rtc->clear(nullptr, color0, GrRenderTargetContext::CanClearFullscreen::kNo); int w = rtc->width(); int h = rtc->height(); int pixelCnt = w * h; SkAutoTMalloc<uint32_t> expectedPixels(pixelCnt); // The clear color is a GrColor, our readback is to kRGBA_8888, which may be different. uint32_t expectedColor0 = 0; uint8_t* expectedBytes0 = SkTCast<uint8_t*>(&expectedColor0); expectedBytes0[0] = GrColorUnpackR(color0); expectedBytes0[1] = GrColorUnpackG(color0); expectedBytes0[2] = GrColorUnpackB(color0); expectedBytes0[3] = GrColorUnpackA(color0); for (int i = 0; i < rtc->width() * rtc->height(); ++i) { expectedPixels.get()[i] = expectedColor0; } // Clear the the top to a different color. GrColor color1 = GrColorPackRGBA(0x1, 0x2, 0x3, 0x4); SkIRect rect = SkIRect::MakeWH(w, h/2); rtc->clear(&rect, color1, GrRenderTargetContext::CanClearFullscreen::kNo); uint32_t expectedColor1 = 0; uint8_t* expectedBytes1 = SkTCast<uint8_t*>(&expectedColor1); expectedBytes1[0] = GrColorUnpackR(color1); expectedBytes1[1] = GrColorUnpackG(color1); expectedBytes1[2] = GrColorUnpackB(color1); expectedBytes1[3] = GrColorUnpackA(color1); for (int y = 0; y < h/2; ++y) { for (int x = 0; x < w; ++x) { expectedPixels.get()[y * h + x] = expectedColor1; } } test_read_pixels(reporter, rtc, expectedPixels.get(), "RectangleTexture-clear"); } }
GrColorComponentFlags componentsWithValue(unsigned value) const { GrColorComponentFlags flags = kNone_GrColorComponentFlags; if ((kR_GrColorComponentFlag & fFlags) && value == GrColorUnpackR(fColor)) { flags |= kR_GrColorComponentFlag; } if ((kG_GrColorComponentFlag & fFlags) && value == GrColorUnpackG(fColor)) { flags |= kG_GrColorComponentFlag; } if ((kB_GrColorComponentFlag & fFlags) && value == GrColorUnpackB(fColor)) { flags |= kB_GrColorComponentFlag; } if ((kA_GrColorComponentFlag & fFlags) && value == GrColorUnpackA(fColor)) { flags |= kA_GrColorComponentFlag; } return flags; }
void onSetData(const GrGLSLProgramDataManager& pdm, const GrProcessor& processor) override { GrColor color = processor.cast<GrConstColorProcessor>().color(); // We use the "illegal" color value as an uninit sentinel. However, ut isn't inherently // illegal to use this processor with unpremul colors. So we correctly handle the case // when the "illegal" color is used but we will always upload it. if (GrColor_ILLEGAL == color || fPrevColor != color) { static const float scale = 1.f / 255.f; float floatColor[4] = { GrColorUnpackR(color) * scale, GrColorUnpackG(color) * scale, GrColorUnpackB(color) * scale, GrColorUnpackA(color) * scale, }; pdm.set4fv(fColorUniform, 1, floatColor); fPrevColor = color; } }
void GrConstColorProcessor::onComputeInvariantOutput(GrInvariantOutput* inout) const { if (kIgnore_InputMode == fMode) { inout->setToOther(kRGBA_GrColorComponentFlags, fColor, GrInvariantOutput::kWillNot_ReadInput); } else { GrColor r = GrColorUnpackR(fColor); bool colorIsSingleChannel = r == GrColorUnpackG(fColor) && r == GrColorUnpackB(fColor) && r == GrColorUnpackA(fColor); if (kModulateRGBA_InputMode == fMode) { if (colorIsSingleChannel) { inout->mulByKnownSingleComponent(r); } else { inout->mulByKnownFourComponents(fColor); } } else { if (colorIsSingleChannel) { inout->mulAlphaByKnownSingleComponent(r); } else { inout->mulAlphaByKnownFourComponents(fColor); } } } }
bool GrTextureToYUVPlanes(GrTexture* texture, const SkISize sizes[3], void* const planes[3], const size_t rowBytes[3], SkYUVColorSpace colorSpace) { if (GrContext* context = texture->getContext()) { // Depending on the relative sizes of the y, u, and v planes we may do 1 to 3 draws/ // readbacks. sk_sp<GrDrawContext> yuvDrawContext; sk_sp<GrDrawContext> yDrawContext; sk_sp<GrDrawContext> uvDrawContext; sk_sp<GrDrawContext> uDrawContext; sk_sp<GrDrawContext> vDrawContext; GrPixelConfig singleChannelPixelConfig; if (context->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) { singleChannelPixelConfig = kAlpha_8_GrPixelConfig; } else { singleChannelPixelConfig = kRGBA_8888_GrPixelConfig; } // We issue draw(s) to convert from RGBA to Y, U, and V. All three planes may have different // sizes however we optimize for two other cases - all planes are the same (1 draw to YUV), // and U and V are the same but Y differs (2 draws, one for Y, one for UV). if (sizes[0] == sizes[1] && sizes[1] == sizes[2]) { yuvDrawContext = context->newDrawContext(SkBackingFit::kApprox, sizes[0].fWidth, sizes[0].fHeight, kRGBA_8888_GrPixelConfig); if (!yuvDrawContext) { return false; } } else { yDrawContext = context->newDrawContext(SkBackingFit::kApprox, sizes[0].fWidth, sizes[0].fHeight, singleChannelPixelConfig); if (!yDrawContext) { return false; } if (sizes[1] == sizes[2]) { // TODO: Add support for GL_RG when available. uvDrawContext = context->newDrawContext(SkBackingFit::kApprox, sizes[1].fWidth, sizes[1].fHeight, kRGBA_8888_GrPixelConfig); if (!uvDrawContext) { return false; } } else { uDrawContext = context->newDrawContext(SkBackingFit::kApprox, sizes[1].fWidth, sizes[1].fHeight, singleChannelPixelConfig); vDrawContext = context->newDrawContext(SkBackingFit::kApprox, sizes[2].fWidth, sizes[2].fHeight, singleChannelPixelConfig); if (!uDrawContext || !vDrawContext) { return false; } } } // Do all the draws before any readback. if (yuvDrawContext) { if (!convert_texture(texture, yuvDrawContext.get(), sizes[0].fWidth, sizes[0].fHeight, colorSpace, GrYUVEffect::MakeRGBToYUV)) { return false; } } else { SkASSERT(yDrawContext); if (!convert_texture(texture, yDrawContext.get(), sizes[0].fWidth, sizes[0].fHeight, colorSpace, GrYUVEffect::MakeRGBToY)) { return false; } if (uvDrawContext) { if (!convert_texture(texture, uvDrawContext.get(), sizes[1].fWidth, sizes[1].fHeight, colorSpace, GrYUVEffect::MakeRGBToUV)) { return false; } } else { SkASSERT(uDrawContext && vDrawContext); if (!convert_texture(texture, uDrawContext.get(), sizes[1].fWidth, sizes[1].fHeight, colorSpace, GrYUVEffect::MakeRGBToU)) { return false; } if (!convert_texture(texture, vDrawContext.get(), sizes[2].fWidth, sizes[2].fHeight, colorSpace, GrYUVEffect::MakeRGBToV)) { return false; } } } if (yuvDrawContext) { SkASSERT(sizes[0] == sizes[1] && sizes[1] == sizes[2]); sk_sp<GrTexture> yuvTex(yuvDrawContext->asTexture()); SkASSERT(yuvTex); SkISize yuvSize = sizes[0]; // We have no kRGB_888 pixel format, so readback rgba and then copy three channels. SkAutoSTMalloc<128 * 128, uint32_t> tempYUV(yuvSize.fWidth * yuvSize.fHeight); if (!yuvTex->readPixels(0, 0, yuvSize.fWidth, yuvSize.fHeight, kRGBA_8888_GrPixelConfig, tempYUV.get(), 0)) { return false; } size_t yRowBytes = rowBytes[0] ? rowBytes[0] : yuvSize.fWidth; size_t uRowBytes = rowBytes[1] ? rowBytes[1] : yuvSize.fWidth; size_t vRowBytes = rowBytes[2] ? rowBytes[2] : yuvSize.fWidth; if (yRowBytes < (size_t)yuvSize.fWidth || uRowBytes < (size_t)yuvSize.fWidth || vRowBytes < (size_t)yuvSize.fWidth) { return false; } for (int j = 0; j < yuvSize.fHeight; ++j) { for (int i = 0; i < yuvSize.fWidth; ++i) { // These writes could surely be made more efficient. uint32_t y = GrColorUnpackR(tempYUV.get()[j * yuvSize.fWidth + i]); uint32_t u = GrColorUnpackG(tempYUV.get()[j * yuvSize.fWidth + i]); uint32_t v = GrColorUnpackB(tempYUV.get()[j * yuvSize.fWidth + i]); uint8_t* yLoc = ((uint8_t*)planes[0]) + j * yRowBytes + i; uint8_t* uLoc = ((uint8_t*)planes[1]) + j * uRowBytes + i; uint8_t* vLoc = ((uint8_t*)planes[2]) + j * vRowBytes + i; *yLoc = y; *uLoc = u; *vLoc = v; } } return true; } else { SkASSERT(yDrawContext); sk_sp<GrTexture> yTex(yDrawContext->asTexture()); SkASSERT(yTex); if (!yTex->readPixels(0, 0, sizes[0].fWidth, sizes[0].fHeight, kAlpha_8_GrPixelConfig, planes[0], rowBytes[0])) { return false; } if (uvDrawContext) { SkASSERT(sizes[1].fWidth == sizes[2].fWidth); sk_sp<GrTexture> uvTex(uvDrawContext->asTexture()); SkASSERT(uvTex); SkISize uvSize = sizes[1]; // We have no kRG_88 pixel format, so readback rgba and then copy two channels. SkAutoSTMalloc<128 * 128, uint32_t> tempUV(uvSize.fWidth * uvSize.fHeight); if (!uvTex->readPixels(0, 0, uvSize.fWidth, uvSize.fHeight, kRGBA_8888_GrPixelConfig, tempUV.get(), 0)) { return false; } size_t uRowBytes = rowBytes[1] ? rowBytes[1] : uvSize.fWidth; size_t vRowBytes = rowBytes[2] ? rowBytes[2] : uvSize.fWidth; if (uRowBytes < (size_t)uvSize.fWidth || vRowBytes < (size_t)uvSize.fWidth) { return false; } for (int j = 0; j < uvSize.fHeight; ++j) { for (int i = 0; i < uvSize.fWidth; ++i) { // These writes could surely be made more efficient. uint32_t u = GrColorUnpackR(tempUV.get()[j * uvSize.fWidth + i]); uint32_t v = GrColorUnpackG(tempUV.get()[j * uvSize.fWidth + i]); uint8_t* uLoc = ((uint8_t*)planes[1]) + j * uRowBytes + i; uint8_t* vLoc = ((uint8_t*)planes[2]) + j * vRowBytes + i; *uLoc = u; *vLoc = v; } } return true; } else { SkASSERT(uDrawContext && vDrawContext); sk_sp<GrTexture> tex(uDrawContext->asTexture()); SkASSERT(tex); if (!tex->readPixels(0, 0, sizes[1].fWidth, sizes[1].fHeight, kAlpha_8_GrPixelConfig, planes[1], rowBytes[1])) { return false; } tex = vDrawContext->asTexture(); SkASSERT(tex); if (!tex->readPixels(0, 0, sizes[2].fWidth, sizes[2].fHeight, kAlpha_8_GrPixelConfig, planes[2], rowBytes[2])) { return false; } return true; } } } return false; }
bool GrGpuGLFixed::flushGraphicsState(GrPrimitiveType type) { bool usingTextures[kNumStages]; for (int s = 0; s < kNumStages; ++s) { usingTextures[s] = VertexUsesStage(s, fGeometrySrc.fVertexLayout); if (usingTextures[s] && fCurrDrawState.fSamplerStates[s].isGradient()) { unimpl("Fixed pipe doesn't support radial/sweep gradients"); return false; } } if (GR_GL_SUPPORT_ES1) { if (BlendCoefReferencesConstant(fCurrDrawState.fSrcBlend) || BlendCoefReferencesConstant(fCurrDrawState.fDstBlend)) { unimpl("ES1 doesn't support blend constant"); return false; } } if (!flushGLStateCommon(type)) { return false; } if (fDirtyFlags.fRenderTargetChanged) { flushProjectionMatrix(); } for (int s = 0; s < kNumStages; ++s) { bool wasUsingTexture = VertexUsesStage(s, fHWGeometryState.fVertexLayout); if (usingTextures[s] != wasUsingTexture) { setTextureUnit(s); if (usingTextures[s]) { GR_GL(Enable(GR_GL_TEXTURE_2D)); } else { GR_GL(Disable(GR_GL_TEXTURE_2D)); } } } uint32_t vertColor = (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit); uint32_t prevVertColor = (fHWGeometryState.fVertexLayout & kColor_VertexLayoutBit); if (vertColor != prevVertColor) { if (vertColor) { GR_GL(ShadeModel(GR_GL_SMOOTH)); // invalidate the immediate mode color fHWDrawState.fColor = GrColor_ILLEGAL; } else { GR_GL(ShadeModel(GR_GL_FLAT)); } } if (!vertColor && fHWDrawState.fColor != fCurrDrawState.fColor) { GR_GL(Color4ub(GrColorUnpackR(fCurrDrawState.fColor), GrColorUnpackG(fCurrDrawState.fColor), GrColorUnpackB(fCurrDrawState.fColor), GrColorUnpackA(fCurrDrawState.fColor))); fHWDrawState.fColor = fCurrDrawState.fColor; } // set texture environment, decide whether we are modulating by RGB or A. for (int s = 0; s < kNumStages; ++s) { if (usingTextures[s]) { GrGLTexture* texture = (GrGLTexture*)fCurrDrawState.fTextures[s]; if (NULL != texture) { TextureEnvRGBOperands nextRGBOperand0 = (GrPixelConfigIsAlphaOnly(texture->config())) ? kAlpha_TextureEnvRGBOperand : kColor_TextureEnvRGBOperand; if (fHWRGBOperand0[s] != nextRGBOperand0) { setTextureUnit(s); GR_GL(TexEnvi(GR_GL_TEXTURE_ENV, GR_GL_OPERAND0_RGB, (nextRGBOperand0==kAlpha_TextureEnvRGBOperand) ? GR_GL_SRC_ALPHA : GR_GL_SRC_COLOR)); fHWRGBOperand0[s] = nextRGBOperand0; } if (((1 << s) & fDirtyFlags.fTextureChangedMask) || (fHWDrawState.fSamplerStates[s].getMatrix() != getSamplerMatrix(s))) { GrMatrix texMat = getSamplerMatrix(s); AdjustTextureMatrix(texture, GrSamplerState::kNormal_SampleMode, &texMat); GrGpuMatrix glm; glm.set(texMat); setTextureUnit(s); GR_GL(MatrixMode(GR_GL_TEXTURE)); GR_GL(LoadMatrixf(glm.fMat)); recordHWSamplerMatrix(s, getSamplerMatrix(s)); } } else { GrAssert(!"Rendering with texture vert flag set but no bound texture"); return false; } } } if (fHWDrawState.fViewMatrix != fCurrDrawState.fViewMatrix) { GrGpuMatrix glm; glm.set(fCurrDrawState.fViewMatrix); GR_GL(MatrixMode(GR_GL_MODELVIEW)); GR_GL(LoadMatrixf(glm.fMat)); fHWDrawState.fViewMatrix = fCurrDrawState.fViewMatrix; } resetDirtyFlags(); return true; }
bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) { if (!flushGLStateCommon(type)) { return false; } if (fDirtyFlags.fRenderTargetChanged) { // our coords are in pixel space and the GL matrices map to NDC // so if the viewport changed, our matrix is now wrong. #if ATTRIBUTE_MATRIX fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix(); #else // we assume all shader matrices may be wrong after viewport changes fProgramCache->invalidateViewMatrices(); #endif } if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) { // invalidate the immediate mode color fHWDrawState.fColor = GrColor_ILLEGAL; } else { if (fHWDrawState.fColor != fCurrDrawState.fColor) { // OpenGL ES only supports the float varities of glVertexAttrib float c[] = { GrColorUnpackR(fCurrDrawState.fColor) / 255.f, GrColorUnpackG(fCurrDrawState.fColor) / 255.f, GrColorUnpackB(fCurrDrawState.fColor) / 255.f, GrColorUnpackA(fCurrDrawState.fColor) / 255.f }; GR_GL(VertexAttrib4fv(COL_ATTR_LOCATION, c)); fHWDrawState.fColor = fCurrDrawState.fColor; } } buildProgram(type); fProgramData = fProgramCache->getProgramData(fCurrentProgram, this); if (fHWProgramID != fProgramData->fProgramID) { GR_GL(UseProgram(fProgramData->fProgramID)); fHWProgramID = fProgramData->fProgramID; } if (!fCurrentProgram.doGLSetup(type, fProgramData)) { return false; } #if ATTRIBUTE_MATRIX GrMatrix& currViewMatrix = fHWDrawState.fViewMatrix; #else GrMatrix& currViewMatrix = fProgramData->fViewMatrix; #endif if (currViewMatrix != fCurrDrawState.fViewMatrix) { flushViewMatrix(); currViewMatrix = fCurrDrawState.fViewMatrix; } for (int s = 0; s < kNumStages; ++s) { GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; if (NULL != texture) { if (-1 != fProgramData->fUniLocations.fStages[s].fTextureMatrixUni && (((1 << s) & fDirtyFlags.fTextureChangedMask) || getHWSamplerMatrix(s) != getSamplerMatrix(s))) { flushTextureMatrix(s); recordHWSamplerMatrix(s, getSamplerMatrix(s)); } } const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s]; if (-1 != fProgramData->fUniLocations.fStages[s].fRadial2Uni && (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() || fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() || fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) { flushRadial2(s); fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1(); fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0(); fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot(); } } resetDirtyFlags(); return true; }
bool GrTextureToYUVPlanes(GrTexture* texture, const SkISize sizes[3], void* const planes[3], const size_t rowBytes[3], SkYUVColorSpace colorSpace) { if (GrContext* context = texture->getContext()) { // Depending on the relative sizes of the y, u, and v planes we may do 1 to 3 draws/ // readbacks. SkAutoTUnref<GrTexture> yuvTex; SkAutoTUnref<GrTexture> yTex; SkAutoTUnref<GrTexture> uvTex; SkAutoTUnref<GrTexture> uTex; SkAutoTUnref<GrTexture> vTex; GrPixelConfig singleChannelPixelConfig; if (context->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) { singleChannelPixelConfig = kAlpha_8_GrPixelConfig; } else { singleChannelPixelConfig = kRGBA_8888_GrPixelConfig; } // We issue draw(s) to convert from RGBA to Y, U, and V. All three planes may have different // sizes however we optimize for two other cases - all planes are the same (1 draw to YUV), // and U and V are the same but Y differs (2 draws, one for Y, one for UV). if (sizes[0] == sizes[1] && sizes[1] == sizes[2]) { GrSurfaceDesc yuvDesc; yuvDesc.fConfig = kRGBA_8888_GrPixelConfig; yuvDesc.fFlags = kRenderTarget_GrSurfaceFlag; yuvDesc.fWidth = sizes[0].fWidth; yuvDesc.fHeight = sizes[0].fHeight; yuvTex.reset(context->textureProvider()->createApproxTexture(yuvDesc)); if (!yuvTex) { return false; } } else { GrSurfaceDesc yDesc; yDesc.fConfig = singleChannelPixelConfig; yDesc.fFlags = kRenderTarget_GrSurfaceFlag; yDesc.fWidth = sizes[0].fWidth; yDesc.fHeight = sizes[0].fHeight; yTex.reset(context->textureProvider()->createApproxTexture(yDesc)); if (!yTex) { return false; } if (sizes[1] == sizes[2]) { GrSurfaceDesc uvDesc; // TODO: Add support for GL_RG when available. uvDesc.fConfig = kRGBA_8888_GrPixelConfig; uvDesc.fFlags = kRenderTarget_GrSurfaceFlag; uvDesc.fWidth = sizes[1].fWidth; uvDesc.fHeight = sizes[1].fHeight; uvTex.reset(context->textureProvider()->createApproxTexture(uvDesc)); if (!uvTex) { return false; } } else { GrSurfaceDesc uvDesc; uvDesc.fConfig = singleChannelPixelConfig; uvDesc.fFlags = kRenderTarget_GrSurfaceFlag; uvDesc.fWidth = sizes[1].fWidth; uvDesc.fHeight = sizes[1].fHeight; uTex.reset(context->textureProvider()->createApproxTexture(uvDesc)); uvDesc.fWidth = sizes[2].fWidth; uvDesc.fHeight = sizes[2].fHeight; vTex.reset(context->textureProvider()->createApproxTexture(uvDesc)); if (!uTex || !vTex) { return false; } } } // Do all the draws before any readback. if (yuvTex) { SkAutoTUnref<GrDrawContext> dc(context->drawContext(yuvTex->asRenderTarget())); if (!dc) { return false; } if (!convert_texture(texture, dc, sizes[0].fWidth, sizes[0].fHeight, colorSpace, GrYUVEffect::CreateRGBToYUV)) { return false; } } else { SkASSERT(yTex); SkAutoTUnref<GrDrawContext> dc(context->drawContext(yTex->asRenderTarget())); if (!dc) { return false; } if (!convert_texture(texture, dc, sizes[0].fWidth, sizes[0].fHeight, colorSpace, GrYUVEffect::CreateRGBToY)) { return false; } if (uvTex) { dc.reset(context->drawContext(uvTex->asRenderTarget())); if (!dc) { return false; } if (!convert_texture(texture, dc, sizes[1].fWidth, sizes[1].fHeight, colorSpace, GrYUVEffect::CreateRGBToUV)) { return false; } } else { SkASSERT(uTex && vTex); dc.reset(context->drawContext(uTex->asRenderTarget())); if (!dc) { return false; } if (!convert_texture(texture, dc, sizes[1].fWidth, sizes[1].fHeight, colorSpace, GrYUVEffect::CreateRGBToU)) { return false; } dc.reset(context->drawContext(vTex->asRenderTarget())); if (!dc) { return false; } if (!convert_texture(texture, dc, sizes[2].fWidth, sizes[2].fHeight, colorSpace, GrYUVEffect::CreateRGBToV)) { return false; } } } if (yuvTex) { SkASSERT(sizes[0] == sizes[1] && sizes[1] == sizes[2]); SkISize yuvSize = sizes[0]; // We have no kRGB_888 pixel format, so readback rgba and then copy three channels. SkAutoSTMalloc<128 * 128, uint32_t> tempYUV(yuvSize.fWidth * yuvSize.fHeight); if (!yuvTex->readPixels(0, 0, yuvSize.fWidth, yuvSize.fHeight, kRGBA_8888_GrPixelConfig, tempYUV.get(), 0)) { return false; } size_t yRowBytes = rowBytes[0] ? rowBytes[0] : yuvSize.fWidth; size_t uRowBytes = rowBytes[1] ? rowBytes[1] : yuvSize.fWidth; size_t vRowBytes = rowBytes[2] ? rowBytes[2] : yuvSize.fWidth; if (yRowBytes < (size_t)yuvSize.fWidth || uRowBytes < (size_t)yuvSize.fWidth || vRowBytes < (size_t)yuvSize.fWidth) { return false; } for (int j = 0; j < yuvSize.fHeight; ++j) { for (int i = 0; i < yuvSize.fWidth; ++i) { // These writes could surely be made more efficient. uint32_t y = GrColorUnpackR(tempYUV.get()[j * yuvSize.fWidth + i]); uint32_t u = GrColorUnpackG(tempYUV.get()[j * yuvSize.fWidth + i]); uint32_t v = GrColorUnpackB(tempYUV.get()[j * yuvSize.fWidth + i]); uint8_t* yLoc = ((uint8_t*)planes[0]) + j * yRowBytes + i; uint8_t* uLoc = ((uint8_t*)planes[1]) + j * uRowBytes + i; uint8_t* vLoc = ((uint8_t*)planes[2]) + j * vRowBytes + i; *yLoc = y; *uLoc = u; *vLoc = v; } } return true; } else { SkASSERT(yTex); if (!yTex->readPixels(0, 0, sizes[0].fWidth, sizes[0].fHeight, kAlpha_8_GrPixelConfig, planes[0], rowBytes[0])) { return false; } if (uvTex) { SkASSERT(sizes[1].fWidth == sizes[2].fWidth); SkISize uvSize = sizes[1]; // We have no kRG_88 pixel format, so readback rgba and then copy two channels. SkAutoSTMalloc<128 * 128, uint32_t> tempUV(uvSize.fWidth * uvSize.fHeight); if (!uvTex->readPixels(0, 0, uvSize.fWidth, uvSize.fHeight, kRGBA_8888_GrPixelConfig, tempUV.get(), 0)) { return false; } size_t uRowBytes = rowBytes[1] ? rowBytes[1] : uvSize.fWidth; size_t vRowBytes = rowBytes[2] ? rowBytes[2] : uvSize.fWidth; if (uRowBytes < (size_t)uvSize.fWidth || vRowBytes < (size_t)uvSize.fWidth) { return false; } for (int j = 0; j < uvSize.fHeight; ++j) { for (int i = 0; i < uvSize.fWidth; ++i) { // These writes could surely be made more efficient. uint32_t u = GrColorUnpackR(tempUV.get()[j * uvSize.fWidth + i]); uint32_t v = GrColorUnpackG(tempUV.get()[j * uvSize.fWidth + i]); uint8_t* uLoc = ((uint8_t*)planes[1]) + j * uRowBytes + i; uint8_t* vLoc = ((uint8_t*)planes[2]) + j * vRowBytes + i; *uLoc = u; *vLoc = v; } } return true; } else { SkASSERT(uTex && vTex); if (!uTex->readPixels(0, 0, sizes[1].fWidth, sizes[1].fHeight, kAlpha_8_GrPixelConfig, planes[1], rowBytes[1])) { return false; } if (!vTex->readPixels(0, 0, sizes[2].fWidth, sizes[2].fHeight, kAlpha_8_GrPixelConfig, planes[2], rowBytes[2])) { return false; } return true; } } } return false; }