1*c8dee2aaSAndroid Build Coastguard Worker/* 2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2018 Google Inc. 3*c8dee2aaSAndroid Build Coastguard Worker * 4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be 5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file. 6*c8dee2aaSAndroid Build Coastguard Worker */ 7*c8dee2aaSAndroid Build Coastguard Worker 8*c8dee2aaSAndroid Build Coastguard Worker#include "src/gpu/ganesh/mtl/GrMtlPipelineState.h" 9*c8dee2aaSAndroid Build Coastguard Worker 10*c8dee2aaSAndroid Build Coastguard Worker#include "src/gpu/ganesh/GrBackendUtils.h" 11*c8dee2aaSAndroid Build Coastguard Worker#include "src/gpu/ganesh/GrFragmentProcessor.h" 12*c8dee2aaSAndroid Build Coastguard Worker#include "src/gpu/ganesh/GrGeometryProcessor.h" 13*c8dee2aaSAndroid Build Coastguard Worker#include "src/gpu/ganesh/GrRenderTarget.h" 14*c8dee2aaSAndroid Build Coastguard Worker#include "src/gpu/ganesh/GrTexture.h" 15*c8dee2aaSAndroid Build Coastguard Worker#include "src/gpu/ganesh/GrXferProcessor.h" 16*c8dee2aaSAndroid Build Coastguard Worker#include "src/gpu/ganesh/effects/GrTextureEffect.h" 17*c8dee2aaSAndroid Build Coastguard Worker#include "src/gpu/ganesh/mtl/GrMtlBuffer.h" 18*c8dee2aaSAndroid Build Coastguard Worker#include "src/gpu/ganesh/mtl/GrMtlFramebuffer.h" 19*c8dee2aaSAndroid Build Coastguard Worker#include "src/gpu/ganesh/mtl/GrMtlGpu.h" 20*c8dee2aaSAndroid Build Coastguard Worker#include "src/gpu/ganesh/mtl/GrMtlRenderCommandEncoder.h" 21*c8dee2aaSAndroid Build Coastguard Worker#include "src/gpu/ganesh/mtl/GrMtlTexture.h" 22*c8dee2aaSAndroid Build Coastguard Worker#include "src/sksl/SkSLCompiler.h" 23*c8dee2aaSAndroid Build Coastguard Worker 24*c8dee2aaSAndroid Build Coastguard Worker#if !__has_feature(objc_arc) 25*c8dee2aaSAndroid Build Coastguard Worker#error This file must be compiled with Arc. Use -fobjc-arc flag 26*c8dee2aaSAndroid Build Coastguard Worker#endif 27*c8dee2aaSAndroid Build Coastguard Worker 28*c8dee2aaSAndroid Build Coastguard WorkerGR_NORETAIN_BEGIN 29*c8dee2aaSAndroid Build Coastguard Worker 30*c8dee2aaSAndroid Build Coastguard WorkerGrMtlPipelineState::SamplerBindings::SamplerBindings(GrSamplerState state, 31*c8dee2aaSAndroid Build Coastguard Worker GrTexture* texture, 32*c8dee2aaSAndroid Build Coastguard Worker GrMtlGpu* gpu) 33*c8dee2aaSAndroid Build Coastguard Worker : fTexture(static_cast<GrMtlTexture*>(texture)->mtlTexture()) { 34*c8dee2aaSAndroid Build Coastguard Worker fSampler = gpu->resourceProvider().findOrCreateCompatibleSampler(state); 35*c8dee2aaSAndroid Build Coastguard Worker gpu->commandBuffer()->addResource(sk_ref_sp<GrManagedResource>(fSampler)); 36*c8dee2aaSAndroid Build Coastguard Worker gpu->commandBuffer()->addGrSurface( 37*c8dee2aaSAndroid Build Coastguard Worker sk_ref_sp<GrSurface>(static_cast<GrMtlTexture*>(texture)->attachment())); 38*c8dee2aaSAndroid Build Coastguard Worker} 39*c8dee2aaSAndroid Build Coastguard Worker 40*c8dee2aaSAndroid Build Coastguard WorkerGrMtlPipelineState::GrMtlPipelineState( 41*c8dee2aaSAndroid Build Coastguard Worker GrMtlGpu* gpu, 42*c8dee2aaSAndroid Build Coastguard Worker sk_sp<GrMtlRenderPipeline> pipeline, 43*c8dee2aaSAndroid Build Coastguard Worker MTLPixelFormat pixelFormat, 44*c8dee2aaSAndroid Build Coastguard Worker const GrGLSLBuiltinUniformHandles& builtinUniformHandles, 45*c8dee2aaSAndroid Build Coastguard Worker const UniformInfoArray& uniforms, 46*c8dee2aaSAndroid Build Coastguard Worker uint32_t uniformBufferSize, 47*c8dee2aaSAndroid Build Coastguard Worker uint32_t numSamplers, 48*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<GrGeometryProcessor::ProgramImpl> gpImpl, 49*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<GrXferProcessor::ProgramImpl> xpImpl, 50*c8dee2aaSAndroid Build Coastguard Worker std::vector<std::unique_ptr<GrFragmentProcessor::ProgramImpl>> fpImpls) 51*c8dee2aaSAndroid Build Coastguard Worker : fGpu(gpu) 52*c8dee2aaSAndroid Build Coastguard Worker , fPipeline(std::move(pipeline)) 53*c8dee2aaSAndroid Build Coastguard Worker , fPixelFormat(pixelFormat) 54*c8dee2aaSAndroid Build Coastguard Worker , fBuiltinUniformHandles(builtinUniformHandles) 55*c8dee2aaSAndroid Build Coastguard Worker , fNumSamplers(numSamplers) 56*c8dee2aaSAndroid Build Coastguard Worker , fGPImpl(std::move(gpImpl)) 57*c8dee2aaSAndroid Build Coastguard Worker , fXPImpl(std::move(xpImpl)) 58*c8dee2aaSAndroid Build Coastguard Worker , fFPImpls(std::move(fpImpls)) 59*c8dee2aaSAndroid Build Coastguard Worker , fDataManager(uniforms, uniformBufferSize) { 60*c8dee2aaSAndroid Build Coastguard Worker (void) fPixelFormat; // Suppress unused-var warning. 61*c8dee2aaSAndroid Build Coastguard Worker} 62*c8dee2aaSAndroid Build Coastguard Worker 63*c8dee2aaSAndroid Build Coastguard Workervoid GrMtlPipelineState::setData(GrMtlFramebuffer* framebuffer, 64*c8dee2aaSAndroid Build Coastguard Worker const GrProgramInfo& programInfo) { 65*c8dee2aaSAndroid Build Coastguard Worker SkISize colorAttachmentDimensions = framebuffer->colorAttachment()->dimensions(); 66*c8dee2aaSAndroid Build Coastguard Worker 67*c8dee2aaSAndroid Build Coastguard Worker this->setRenderTargetState(colorAttachmentDimensions, programInfo.origin()); 68*c8dee2aaSAndroid Build Coastguard Worker fGPImpl->setData(fDataManager, *fGpu->caps()->shaderCaps(), programInfo.geomProc()); 69*c8dee2aaSAndroid Build Coastguard Worker 70*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < programInfo.pipeline().numFragmentProcessors(); ++i) { 71*c8dee2aaSAndroid Build Coastguard Worker const auto& fp = programInfo.pipeline().getFragmentProcessor(i); 72*c8dee2aaSAndroid Build Coastguard Worker fp.visitWithImpls([&](const GrFragmentProcessor& fp, 73*c8dee2aaSAndroid Build Coastguard Worker GrFragmentProcessor::ProgramImpl& impl) { 74*c8dee2aaSAndroid Build Coastguard Worker impl.setData(fDataManager, fp); 75*c8dee2aaSAndroid Build Coastguard Worker }, *fFPImpls[i]); 76*c8dee2aaSAndroid Build Coastguard Worker } 77*c8dee2aaSAndroid Build Coastguard Worker 78*c8dee2aaSAndroid Build Coastguard Worker programInfo.pipeline().setDstTextureUniforms(fDataManager, &fBuiltinUniformHandles); 79*c8dee2aaSAndroid Build Coastguard Worker fXPImpl->setData(fDataManager, programInfo.pipeline().getXferProcessor()); 80*c8dee2aaSAndroid Build Coastguard Worker 81*c8dee2aaSAndroid Build Coastguard Worker fDataManager.resetDirtyBits(); 82*c8dee2aaSAndroid Build Coastguard Worker 83*c8dee2aaSAndroid Build Coastguard Worker#ifdef SK_DEBUG 84*c8dee2aaSAndroid Build Coastguard Worker if (programInfo.isStencilEnabled()) { 85*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(const GrAttachment* stencil = framebuffer->stencilAttachment()); 86*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(stencil); 87*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(GrBackendFormatStencilBits(stencil->backendFormat()) == 8); 88*c8dee2aaSAndroid Build Coastguard Worker } 89*c8dee2aaSAndroid Build Coastguard Worker#endif 90*c8dee2aaSAndroid Build Coastguard Worker 91*c8dee2aaSAndroid Build Coastguard Worker fStencil = programInfo.nonGLStencilSettings(); 92*c8dee2aaSAndroid Build Coastguard Worker fGpu->commandBuffer()->addResource(fPipeline); 93*c8dee2aaSAndroid Build Coastguard Worker} 94*c8dee2aaSAndroid Build Coastguard Worker 95*c8dee2aaSAndroid Build Coastguard Workervoid GrMtlPipelineState::setTextures(const GrGeometryProcessor& geomProc, 96*c8dee2aaSAndroid Build Coastguard Worker const GrPipeline& pipeline, 97*c8dee2aaSAndroid Build Coastguard Worker const GrSurfaceProxy* const geomProcTextures[]) { 98*c8dee2aaSAndroid Build Coastguard Worker fSamplerBindings.clear(); 99*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < geomProc.numTextureSamplers(); ++i) { 100*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(geomProcTextures[i]->asTextureProxy()); 101*c8dee2aaSAndroid Build Coastguard Worker const auto& sampler = geomProc.textureSampler(i); 102*c8dee2aaSAndroid Build Coastguard Worker auto texture = static_cast<GrMtlTexture*>(geomProcTextures[i]->peekTexture()); 103*c8dee2aaSAndroid Build Coastguard Worker fSamplerBindings.emplace_back(sampler.samplerState(), texture, fGpu); 104*c8dee2aaSAndroid Build Coastguard Worker } 105*c8dee2aaSAndroid Build Coastguard Worker 106*c8dee2aaSAndroid Build Coastguard Worker if (GrTextureProxy* dstTextureProxy = pipeline.dstProxyView().asTextureProxy()) { 107*c8dee2aaSAndroid Build Coastguard Worker fSamplerBindings.emplace_back( 108*c8dee2aaSAndroid Build Coastguard Worker GrSamplerState::Filter::kNearest, dstTextureProxy->peekTexture(), fGpu); 109*c8dee2aaSAndroid Build Coastguard Worker } 110*c8dee2aaSAndroid Build Coastguard Worker 111*c8dee2aaSAndroid Build Coastguard Worker pipeline.visitTextureEffects([&](const GrTextureEffect& te) { 112*c8dee2aaSAndroid Build Coastguard Worker fSamplerBindings.emplace_back(te.samplerState(), te.texture(), fGpu); 113*c8dee2aaSAndroid Build Coastguard Worker }); 114*c8dee2aaSAndroid Build Coastguard Worker 115*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fNumSamplers == fSamplerBindings.size()); 116*c8dee2aaSAndroid Build Coastguard Worker} 117*c8dee2aaSAndroid Build Coastguard Worker 118*c8dee2aaSAndroid Build Coastguard Workervoid GrMtlPipelineState::setDrawState(GrMtlRenderCommandEncoder* renderCmdEncoder, 119*c8dee2aaSAndroid Build Coastguard Worker const skgpu::Swizzle& writeSwizzle, 120*c8dee2aaSAndroid Build Coastguard Worker const GrXferProcessor& xferProcessor) { 121*c8dee2aaSAndroid Build Coastguard Worker this->bindUniforms(renderCmdEncoder); 122*c8dee2aaSAndroid Build Coastguard Worker this->setBlendConstants(renderCmdEncoder, writeSwizzle, xferProcessor); 123*c8dee2aaSAndroid Build Coastguard Worker this->setDepthStencilState(renderCmdEncoder); 124*c8dee2aaSAndroid Build Coastguard Worker} 125*c8dee2aaSAndroid Build Coastguard Worker 126*c8dee2aaSAndroid Build Coastguard Workervoid GrMtlPipelineState::bindUniforms(GrMtlRenderCommandEncoder* renderCmdEncoder) { 127*c8dee2aaSAndroid Build Coastguard Worker fDataManager.uploadAndBindUniformBuffers(fGpu, renderCmdEncoder); 128*c8dee2aaSAndroid Build Coastguard Worker} 129*c8dee2aaSAndroid Build Coastguard Worker 130*c8dee2aaSAndroid Build Coastguard Workervoid GrMtlPipelineState::bindTextures(GrMtlRenderCommandEncoder* renderCmdEncoder) { 131*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fNumSamplers == fSamplerBindings.size()); 132*c8dee2aaSAndroid Build Coastguard Worker for (int index = 0; index < fNumSamplers; ++index) { 133*c8dee2aaSAndroid Build Coastguard Worker renderCmdEncoder->setFragmentTexture(fSamplerBindings[index].fTexture, index); 134*c8dee2aaSAndroid Build Coastguard Worker renderCmdEncoder->setFragmentSamplerState(fSamplerBindings[index].fSampler, index); 135*c8dee2aaSAndroid Build Coastguard Worker } 136*c8dee2aaSAndroid Build Coastguard Worker} 137*c8dee2aaSAndroid Build Coastguard Worker 138*c8dee2aaSAndroid Build Coastguard Workervoid GrMtlPipelineState::setRenderTargetState(SkISize colorAttachmentDimensions, 139*c8dee2aaSAndroid Build Coastguard Worker GrSurfaceOrigin origin) { 140*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fBuiltinUniformHandles.fRTAdjustmentUni.isValid()); 141*c8dee2aaSAndroid Build Coastguard Worker if (fRenderTargetState.fRenderTargetOrigin != origin || 142*c8dee2aaSAndroid Build Coastguard Worker fRenderTargetState.fRenderTargetSize != colorAttachmentDimensions) { 143*c8dee2aaSAndroid Build Coastguard Worker fRenderTargetState.fRenderTargetSize = colorAttachmentDimensions; 144*c8dee2aaSAndroid Build Coastguard Worker fRenderTargetState.fRenderTargetOrigin = origin; 145*c8dee2aaSAndroid Build Coastguard Worker 146*c8dee2aaSAndroid Build Coastguard Worker // The client will mark a swap buffer as kTopLeft when making a SkSurface because 147*c8dee2aaSAndroid Build Coastguard Worker // Metal's framebuffer space has (0, 0) at the top left. This agrees with Skia's device 148*c8dee2aaSAndroid Build Coastguard Worker // coords. However, in NDC (-1, -1) is the bottom left. So we flip when origin is kTopLeft. 149*c8dee2aaSAndroid Build Coastguard Worker bool flip = (origin == kTopLeft_GrSurfaceOrigin); 150*c8dee2aaSAndroid Build Coastguard Worker std::array<float, 4> v = SkSL::Compiler::GetRTAdjustVector(colorAttachmentDimensions, flip); 151*c8dee2aaSAndroid Build Coastguard Worker fDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, v.data()); 152*c8dee2aaSAndroid Build Coastguard Worker if (fBuiltinUniformHandles.fRTFlipUni.isValid()) { 153*c8dee2aaSAndroid Build Coastguard Worker // Note above that framebuffer space has origin top left. So we need !flip here. 154*c8dee2aaSAndroid Build Coastguard Worker std::array<float, 2> d = 155*c8dee2aaSAndroid Build Coastguard Worker SkSL::Compiler::GetRTFlipVector(colorAttachmentDimensions.height(), !flip); 156*c8dee2aaSAndroid Build Coastguard Worker fDataManager.set2fv(fBuiltinUniformHandles.fRTFlipUni, 1, d.data()); 157*c8dee2aaSAndroid Build Coastguard Worker } 158*c8dee2aaSAndroid Build Coastguard Worker } 159*c8dee2aaSAndroid Build Coastguard Worker} 160*c8dee2aaSAndroid Build Coastguard Worker 161*c8dee2aaSAndroid Build Coastguard Workervoid GrMtlPipelineState::setBlendConstants(GrMtlRenderCommandEncoder* renderCmdEncoder, 162*c8dee2aaSAndroid Build Coastguard Worker const skgpu::Swizzle& swizzle, 163*c8dee2aaSAndroid Build Coastguard Worker const GrXferProcessor& xferProcessor) { 164*c8dee2aaSAndroid Build Coastguard Worker if (!renderCmdEncoder) { 165*c8dee2aaSAndroid Build Coastguard Worker return; 166*c8dee2aaSAndroid Build Coastguard Worker } 167*c8dee2aaSAndroid Build Coastguard Worker 168*c8dee2aaSAndroid Build Coastguard Worker const skgpu::BlendInfo& blendInfo = xferProcessor.getBlendInfo(); 169*c8dee2aaSAndroid Build Coastguard Worker skgpu::BlendCoeff srcCoeff = blendInfo.fSrcBlend; 170*c8dee2aaSAndroid Build Coastguard Worker skgpu::BlendCoeff dstCoeff = blendInfo.fDstBlend; 171*c8dee2aaSAndroid Build Coastguard Worker if (skgpu::BlendCoeffRefsConstant(srcCoeff) || skgpu::BlendCoeffRefsConstant(dstCoeff)) { 172*c8dee2aaSAndroid Build Coastguard Worker // Swizzle the blend to match what the shader will output. 173*c8dee2aaSAndroid Build Coastguard Worker SkPMColor4f blendConst = swizzle.applyTo(blendInfo.fBlendConstant); 174*c8dee2aaSAndroid Build Coastguard Worker 175*c8dee2aaSAndroid Build Coastguard Worker renderCmdEncoder->setBlendColor(blendConst); 176*c8dee2aaSAndroid Build Coastguard Worker } 177*c8dee2aaSAndroid Build Coastguard Worker} 178*c8dee2aaSAndroid Build Coastguard Worker 179*c8dee2aaSAndroid Build Coastguard Workervoid GrMtlPipelineState::setDepthStencilState(GrMtlRenderCommandEncoder* renderCmdEncoder) { 180*c8dee2aaSAndroid Build Coastguard Worker const GrSurfaceOrigin& origin = fRenderTargetState.fRenderTargetOrigin; 181*c8dee2aaSAndroid Build Coastguard Worker GrMtlDepthStencil* state = 182*c8dee2aaSAndroid Build Coastguard Worker fGpu->resourceProvider().findOrCreateCompatibleDepthStencilState(fStencil, origin); 183*c8dee2aaSAndroid Build Coastguard Worker if (!fStencil.isDisabled()) { 184*c8dee2aaSAndroid Build Coastguard Worker if (fStencil.isTwoSided()) { 185*c8dee2aaSAndroid Build Coastguard Worker if (@available(macOS 10.11, iOS 9.0, tvOS 9.0, *)) { 186*c8dee2aaSAndroid Build Coastguard Worker renderCmdEncoder->setStencilFrontBackReferenceValues( 187*c8dee2aaSAndroid Build Coastguard Worker fStencil.postOriginCCWFace(origin).fRef, 188*c8dee2aaSAndroid Build Coastguard Worker fStencil.postOriginCWFace(origin).fRef); 189*c8dee2aaSAndroid Build Coastguard Worker } else { 190*c8dee2aaSAndroid Build Coastguard Worker // Two-sided stencil not supported on older versions of iOS 191*c8dee2aaSAndroid Build Coastguard Worker // TODO: Find a way to recover from this 192*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(false); 193*c8dee2aaSAndroid Build Coastguard Worker } 194*c8dee2aaSAndroid Build Coastguard Worker } else { 195*c8dee2aaSAndroid Build Coastguard Worker renderCmdEncoder->setStencilReferenceValue(fStencil.singleSidedFace().fRef); 196*c8dee2aaSAndroid Build Coastguard Worker } 197*c8dee2aaSAndroid Build Coastguard Worker } 198*c8dee2aaSAndroid Build Coastguard Worker renderCmdEncoder->setDepthStencilState(state->mtlDepthStencil()); 199*c8dee2aaSAndroid Build Coastguard Worker fGpu->commandBuffer()->addResource(sk_ref_sp<GrManagedResource>(state)); 200*c8dee2aaSAndroid Build Coastguard Worker} 201*c8dee2aaSAndroid Build Coastguard Worker 202*c8dee2aaSAndroid Build Coastguard Workervoid GrMtlPipelineState::SetDynamicScissorRectState(GrMtlRenderCommandEncoder* renderCmdEncoder, 203*c8dee2aaSAndroid Build Coastguard Worker SkISize colorAttachmentDimensions, 204*c8dee2aaSAndroid Build Coastguard Worker GrSurfaceOrigin rtOrigin, 205*c8dee2aaSAndroid Build Coastguard Worker SkIRect scissorRect) { 206*c8dee2aaSAndroid Build Coastguard Worker if (!scissorRect.intersect(SkIRect::MakeWH(colorAttachmentDimensions.width(), 207*c8dee2aaSAndroid Build Coastguard Worker colorAttachmentDimensions.height()))) { 208*c8dee2aaSAndroid Build Coastguard Worker scissorRect.setEmpty(); 209*c8dee2aaSAndroid Build Coastguard Worker } 210*c8dee2aaSAndroid Build Coastguard Worker 211*c8dee2aaSAndroid Build Coastguard Worker MTLScissorRect scissor; 212*c8dee2aaSAndroid Build Coastguard Worker scissor.x = scissorRect.fLeft; 213*c8dee2aaSAndroid Build Coastguard Worker scissor.width = scissorRect.width(); 214*c8dee2aaSAndroid Build Coastguard Worker if (kTopLeft_GrSurfaceOrigin == rtOrigin) { 215*c8dee2aaSAndroid Build Coastguard Worker scissor.y = scissorRect.fTop; 216*c8dee2aaSAndroid Build Coastguard Worker } else { 217*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(kBottomLeft_GrSurfaceOrigin == rtOrigin); 218*c8dee2aaSAndroid Build Coastguard Worker scissor.y = colorAttachmentDimensions.height() - scissorRect.fBottom; 219*c8dee2aaSAndroid Build Coastguard Worker } 220*c8dee2aaSAndroid Build Coastguard Worker scissor.height = scissorRect.height(); 221*c8dee2aaSAndroid Build Coastguard Worker 222*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(scissor.x >= 0); 223*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(scissor.y >= 0); 224*c8dee2aaSAndroid Build Coastguard Worker 225*c8dee2aaSAndroid Build Coastguard Worker renderCmdEncoder->setScissorRect(scissor); 226*c8dee2aaSAndroid Build Coastguard Worker} 227*c8dee2aaSAndroid Build Coastguard Worker 228*c8dee2aaSAndroid Build Coastguard Workerbool GrMtlPipelineState::doesntSampleAttachment( 229*c8dee2aaSAndroid Build Coastguard Worker const MTLRenderPassAttachmentDescriptor* attachment) const { 230*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < fSamplerBindings.size(); ++i) { 231*c8dee2aaSAndroid Build Coastguard Worker if (attachment.texture == fSamplerBindings[i].fTexture || 232*c8dee2aaSAndroid Build Coastguard Worker attachment.resolveTexture == fSamplerBindings[i].fTexture) { 233*c8dee2aaSAndroid Build Coastguard Worker return false; 234*c8dee2aaSAndroid Build Coastguard Worker } 235*c8dee2aaSAndroid Build Coastguard Worker } 236*c8dee2aaSAndroid Build Coastguard Worker return true; 237*c8dee2aaSAndroid Build Coastguard Worker} 238*c8dee2aaSAndroid Build Coastguard Worker 239*c8dee2aaSAndroid Build Coastguard WorkerGR_NORETAIN_END 240