123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251 |
- /*
- * Copyright 2011 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #include "include/core/SkPixmap.h"
- #include "include/core/SkStrokeRec.h"
- #include "include/core/SkTypes.h"
- #include "include/gpu/GrBackendSemaphore.h"
- #include "include/gpu/GrBackendSurface.h"
- #include "include/gpu/GrTypes.h"
- #include "include/private/SkHalf.h"
- #include "include/private/SkTemplates.h"
- #include "include/private/SkTo.h"
- #include "src/core/SkAutoMalloc.h"
- #include "src/core/SkConvertPixels.h"
- #include "src/core/SkMakeUnique.h"
- #include "src/core/SkMipMap.h"
- #include "src/core/SkTraceEvent.h"
- #include "src/gpu/GrContextPriv.h"
- #include "src/gpu/GrCpuBuffer.h"
- #include "src/gpu/GrDataUtils.h"
- #include "src/gpu/GrFixedClip.h"
- #include "src/gpu/GrGpuResourcePriv.h"
- #include "src/gpu/GrMesh.h"
- #include "src/gpu/GrPipeline.h"
- #include "src/gpu/GrRenderTargetPriv.h"
- #include "src/gpu/GrShaderCaps.h"
- #include "src/gpu/GrSurfaceProxyPriv.h"
- #include "src/gpu/GrTexturePriv.h"
- #include "src/gpu/gl/GrGLBuffer.h"
- #include "src/gpu/gl/GrGLGpu.h"
- #include "src/gpu/gl/GrGLGpuCommandBuffer.h"
- #include "src/gpu/gl/GrGLSemaphore.h"
- #include "src/gpu/gl/GrGLStencilAttachment.h"
- #include "src/gpu/gl/GrGLTextureRenderTarget.h"
- #include "src/gpu/gl/builders/GrGLShaderStringBuilder.h"
- #include "src/sksl/SkSLCompiler.h"
- #include <cmath>
- #define GL_CALL(X) GR_GL_CALL(this->glInterface(), X)
- #define GL_CALL_RET(RET, X) GR_GL_CALL_RET(this->glInterface(), RET, X)
- #if GR_GL_CHECK_ALLOC_WITH_GET_ERROR
- #define CLEAR_ERROR_BEFORE_ALLOC(iface) GrGLClearErr(iface)
- #define GL_ALLOC_CALL(iface, call) GR_GL_CALL_NOERRCHECK(iface, call)
- #define CHECK_ALLOC_ERROR(iface) GR_GL_GET_ERROR(iface)
- #else
- #define CLEAR_ERROR_BEFORE_ALLOC(iface)
- #define GL_ALLOC_CALL(iface, call) GR_GL_CALL(iface, call)
- #define CHECK_ALLOC_ERROR(iface) GR_GL_NO_ERROR
- #endif
- //#define USE_NSIGHT
- ///////////////////////////////////////////////////////////////////////////////
- static const GrGLenum gXfermodeEquation2Blend[] = {
- // Basic OpenGL blend equations.
- GR_GL_FUNC_ADD,
- GR_GL_FUNC_SUBTRACT,
- GR_GL_FUNC_REVERSE_SUBTRACT,
- // GL_KHR_blend_equation_advanced.
- GR_GL_SCREEN,
- GR_GL_OVERLAY,
- GR_GL_DARKEN,
- GR_GL_LIGHTEN,
- GR_GL_COLORDODGE,
- GR_GL_COLORBURN,
- GR_GL_HARDLIGHT,
- GR_GL_SOFTLIGHT,
- GR_GL_DIFFERENCE,
- GR_GL_EXCLUSION,
- GR_GL_MULTIPLY,
- GR_GL_HSL_HUE,
- GR_GL_HSL_SATURATION,
- GR_GL_HSL_COLOR,
- GR_GL_HSL_LUMINOSITY,
- // Illegal... needs to map to something.
- GR_GL_FUNC_ADD,
- };
- GR_STATIC_ASSERT(0 == kAdd_GrBlendEquation);
- GR_STATIC_ASSERT(1 == kSubtract_GrBlendEquation);
- GR_STATIC_ASSERT(2 == kReverseSubtract_GrBlendEquation);
- GR_STATIC_ASSERT(3 == kScreen_GrBlendEquation);
- GR_STATIC_ASSERT(4 == kOverlay_GrBlendEquation);
- GR_STATIC_ASSERT(5 == kDarken_GrBlendEquation);
- GR_STATIC_ASSERT(6 == kLighten_GrBlendEquation);
- GR_STATIC_ASSERT(7 == kColorDodge_GrBlendEquation);
- GR_STATIC_ASSERT(8 == kColorBurn_GrBlendEquation);
- GR_STATIC_ASSERT(9 == kHardLight_GrBlendEquation);
- GR_STATIC_ASSERT(10 == kSoftLight_GrBlendEquation);
- GR_STATIC_ASSERT(11 == kDifference_GrBlendEquation);
- GR_STATIC_ASSERT(12 == kExclusion_GrBlendEquation);
- GR_STATIC_ASSERT(13 == kMultiply_GrBlendEquation);
- GR_STATIC_ASSERT(14 == kHSLHue_GrBlendEquation);
- GR_STATIC_ASSERT(15 == kHSLSaturation_GrBlendEquation);
- GR_STATIC_ASSERT(16 == kHSLColor_GrBlendEquation);
- GR_STATIC_ASSERT(17 == kHSLLuminosity_GrBlendEquation);
- GR_STATIC_ASSERT(SK_ARRAY_COUNT(gXfermodeEquation2Blend) == kGrBlendEquationCnt);
- static const GrGLenum gXfermodeCoeff2Blend[] = {
- GR_GL_ZERO,
- GR_GL_ONE,
- GR_GL_SRC_COLOR,
- GR_GL_ONE_MINUS_SRC_COLOR,
- GR_GL_DST_COLOR,
- GR_GL_ONE_MINUS_DST_COLOR,
- GR_GL_SRC_ALPHA,
- GR_GL_ONE_MINUS_SRC_ALPHA,
- GR_GL_DST_ALPHA,
- GR_GL_ONE_MINUS_DST_ALPHA,
- GR_GL_CONSTANT_COLOR,
- GR_GL_ONE_MINUS_CONSTANT_COLOR,
- GR_GL_CONSTANT_ALPHA,
- GR_GL_ONE_MINUS_CONSTANT_ALPHA,
- // extended blend coeffs
- GR_GL_SRC1_COLOR,
- GR_GL_ONE_MINUS_SRC1_COLOR,
- GR_GL_SRC1_ALPHA,
- GR_GL_ONE_MINUS_SRC1_ALPHA,
- // Illegal... needs to map to something.
- GR_GL_ZERO,
- };
- bool GrGLGpu::BlendCoeffReferencesConstant(GrBlendCoeff coeff) {
- static const bool gCoeffReferencesBlendConst[] = {
- false,
- false,
- false,
- false,
- false,
- false,
- false,
- false,
- false,
- false,
- true,
- true,
- true,
- true,
- // extended blend coeffs
- false,
- false,
- false,
- false,
- // Illegal.
- false,
- };
- return gCoeffReferencesBlendConst[coeff];
- GR_STATIC_ASSERT(kGrBlendCoeffCnt == SK_ARRAY_COUNT(gCoeffReferencesBlendConst));
- GR_STATIC_ASSERT(0 == kZero_GrBlendCoeff);
- GR_STATIC_ASSERT(1 == kOne_GrBlendCoeff);
- GR_STATIC_ASSERT(2 == kSC_GrBlendCoeff);
- GR_STATIC_ASSERT(3 == kISC_GrBlendCoeff);
- GR_STATIC_ASSERT(4 == kDC_GrBlendCoeff);
- GR_STATIC_ASSERT(5 == kIDC_GrBlendCoeff);
- GR_STATIC_ASSERT(6 == kSA_GrBlendCoeff);
- GR_STATIC_ASSERT(7 == kISA_GrBlendCoeff);
- GR_STATIC_ASSERT(8 == kDA_GrBlendCoeff);
- GR_STATIC_ASSERT(9 == kIDA_GrBlendCoeff);
- GR_STATIC_ASSERT(10 == kConstC_GrBlendCoeff);
- GR_STATIC_ASSERT(11 == kIConstC_GrBlendCoeff);
- GR_STATIC_ASSERT(12 == kConstA_GrBlendCoeff);
- GR_STATIC_ASSERT(13 == kIConstA_GrBlendCoeff);
- GR_STATIC_ASSERT(14 == kS2C_GrBlendCoeff);
- GR_STATIC_ASSERT(15 == kIS2C_GrBlendCoeff);
- GR_STATIC_ASSERT(16 == kS2A_GrBlendCoeff);
- GR_STATIC_ASSERT(17 == kIS2A_GrBlendCoeff);
- // assertion for gXfermodeCoeff2Blend have to be in GrGpu scope
- GR_STATIC_ASSERT(kGrBlendCoeffCnt == SK_ARRAY_COUNT(gXfermodeCoeff2Blend));
- }
- //////////////////////////////////////////////////////////////////////////////
- static int gl_target_to_binding_index(GrGLenum target) {
- switch (target) {
- case GR_GL_TEXTURE_2D:
- return 0;
- case GR_GL_TEXTURE_RECTANGLE:
- return 1;
- case GR_GL_TEXTURE_EXTERNAL:
- return 2;
- }
- SK_ABORT("Unexpected GL texture target.");
- return 0;
- }
- GrGpuResource::UniqueID GrGLGpu::TextureUnitBindings::boundID(GrGLenum target) const {
- return fTargetBindings[gl_target_to_binding_index(target)].fBoundResourceID;
- }
- bool GrGLGpu::TextureUnitBindings::hasBeenModified(GrGLenum target) const {
- return fTargetBindings[gl_target_to_binding_index(target)].fHasBeenModified;
- }
- void GrGLGpu::TextureUnitBindings::setBoundID(GrGLenum target, GrGpuResource::UniqueID resourceID) {
- int targetIndex = gl_target_to_binding_index(target);
- fTargetBindings[targetIndex].fBoundResourceID = resourceID;
- fTargetBindings[targetIndex].fHasBeenModified = true;
- }
- void GrGLGpu::TextureUnitBindings::invalidateForScratchUse(GrGLenum target) {
- this->setBoundID(target, GrGpuResource::UniqueID());
- }
- void GrGLGpu::TextureUnitBindings::invalidateAllTargets(bool markUnmodified) {
- for (auto& targetBinding : fTargetBindings) {
- targetBinding.fBoundResourceID.makeInvalid();
- if (markUnmodified) {
- targetBinding.fHasBeenModified = false;
- }
- }
- }
- //////////////////////////////////////////////////////////////////////////////
- static GrGLenum filter_to_gl_mag_filter(GrSamplerState::Filter filter) {
- switch (filter) {
- case GrSamplerState::Filter::kNearest: return GR_GL_NEAREST;
- case GrSamplerState::Filter::kBilerp: return GR_GL_LINEAR;
- case GrSamplerState::Filter::kMipMap: return GR_GL_LINEAR;
- }
- SK_ABORT("Unknown filter");
- return 0;
- }
- static GrGLenum filter_to_gl_min_filter(GrSamplerState::Filter filter) {
- switch (filter) {
- case GrSamplerState::Filter::kNearest: return GR_GL_NEAREST;
- case GrSamplerState::Filter::kBilerp: return GR_GL_LINEAR;
- case GrSamplerState::Filter::kMipMap: return GR_GL_LINEAR_MIPMAP_LINEAR;
- }
- SK_ABORT("Unknown filter");
- return 0;
- }
- static inline GrGLenum wrap_mode_to_gl_wrap(GrSamplerState::WrapMode wrapMode,
- const GrCaps& caps) {
- switch (wrapMode) {
- case GrSamplerState::WrapMode::kClamp: return GR_GL_CLAMP_TO_EDGE;
- case GrSamplerState::WrapMode::kRepeat: return GR_GL_REPEAT;
- case GrSamplerState::WrapMode::kMirrorRepeat: return GR_GL_MIRRORED_REPEAT;
- case GrSamplerState::WrapMode::kClampToBorder:
- // May not be supported but should have been caught earlier
- SkASSERT(caps.clampToBorderSupport());
- return GR_GL_CLAMP_TO_BORDER;
- }
- SK_ABORT("Unknown wrap mode");
- return 0;
- }
- ///////////////////////////////////////////////////////////////////////////////
- class GrGLGpu::SamplerObjectCache {
- public:
- SamplerObjectCache(GrGLGpu* gpu) : fGpu(gpu) {
- fNumTextureUnits = fGpu->glCaps().shaderCaps()->maxFragmentSamplers();
- fHWBoundSamplers.reset(new GrGLuint[fNumTextureUnits]);
- std::fill_n(fHWBoundSamplers.get(), fNumTextureUnits, 0);
- std::fill_n(fSamplers, kNumSamplers, 0);
- }
- ~SamplerObjectCache() {
- if (!fNumTextureUnits) {
- // We've already been abandoned.
- return;
- }
- for (GrGLuint sampler : fSamplers) {
- // The spec states that "zero" values should be silently ignored, however they still
- // trigger GL errors on some NVIDIA platforms.
- if (sampler) {
- GR_GL_CALL(fGpu->glInterface(), DeleteSamplers(1, &sampler));
- }
- }
- }
- void bindSampler(int unitIdx, const GrSamplerState& state) {
- int index = StateToIndex(state);
- if (!fSamplers[index]) {
- GrGLuint s;
- GR_GL_CALL(fGpu->glInterface(), GenSamplers(1, &s));
- if (!s) {
- return;
- }
- fSamplers[index] = s;
- auto minFilter = filter_to_gl_min_filter(state.filter());
- auto magFilter = filter_to_gl_mag_filter(state.filter());
- auto wrapX = wrap_mode_to_gl_wrap(state.wrapModeX(), fGpu->glCaps());
- auto wrapY = wrap_mode_to_gl_wrap(state.wrapModeY(), fGpu->glCaps());
- GR_GL_CALL(fGpu->glInterface(),
- SamplerParameteri(s, GR_GL_TEXTURE_MIN_FILTER, minFilter));
- GR_GL_CALL(fGpu->glInterface(),
- SamplerParameteri(s, GR_GL_TEXTURE_MAG_FILTER, magFilter));
- GR_GL_CALL(fGpu->glInterface(), SamplerParameteri(s, GR_GL_TEXTURE_WRAP_S, wrapX));
- GR_GL_CALL(fGpu->glInterface(), SamplerParameteri(s, GR_GL_TEXTURE_WRAP_T, wrapY));
- }
- if (fHWBoundSamplers[unitIdx] != fSamplers[index]) {
- GR_GL_CALL(fGpu->glInterface(), BindSampler(unitIdx, fSamplers[index]));
- fHWBoundSamplers[unitIdx] = fSamplers[index];
- }
- }
- void invalidateBindings() {
- // When we have sampler support we always use samplers. So setting these to zero will cause
- // a rebind on next usage.
- std::fill_n(fHWBoundSamplers.get(), fNumTextureUnits, 0);
- }
- void abandon() {
- fHWBoundSamplers.reset();
- fNumTextureUnits = 0;
- }
- void release() {
- if (!fNumTextureUnits) {
- // We've already been abandoned.
- return;
- }
- GR_GL_CALL(fGpu->glInterface(), DeleteSamplers(kNumSamplers, fSamplers));
- std::fill_n(fSamplers, kNumSamplers, 0);
- // Deleting a bound sampler implicitly binds sampler 0.
- std::fill_n(fHWBoundSamplers.get(), fNumTextureUnits, 0);
- }
- private:
- static int StateToIndex(const GrSamplerState& state) {
- int filter = static_cast<int>(state.filter());
- SkASSERT(filter >= 0 && filter < 3);
- int wrapX = static_cast<int>(state.wrapModeX());
- SkASSERT(wrapX >= 0 && wrapX < 4);
- int wrapY = static_cast<int>(state.wrapModeY());
- SkASSERT(wrapY >= 0 && wrapY < 4);
- int idx = 16 * filter + 4 * wrapX + wrapY;
- SkASSERT(idx < kNumSamplers);
- return idx;
- }
- GrGLGpu* fGpu;
- static constexpr int kNumSamplers = 48;
- std::unique_ptr<GrGLuint[]> fHWBoundSamplers;
- GrGLuint fSamplers[kNumSamplers];
- int fNumTextureUnits;
- };
- ///////////////////////////////////////////////////////////////////////////////
- sk_sp<GrGpu> GrGLGpu::Make(sk_sp<const GrGLInterface> interface, const GrContextOptions& options,
- GrContext* context) {
- if (!interface) {
- interface = GrGLMakeNativeInterface();
- // For clients that have written their own GrGLCreateNativeInterface and haven't yet updated
- // to GrGLMakeNativeInterface.
- if (!interface) {
- interface = sk_ref_sp(GrGLCreateNativeInterface());
- }
- if (!interface) {
- return nullptr;
- }
- }
- #ifdef USE_NSIGHT
- const_cast<GrContextOptions&>(options).fSuppressPathRendering = true;
- #endif
- auto glContext = GrGLContext::Make(std::move(interface), options);
- if (!glContext) {
- return nullptr;
- }
- return sk_sp<GrGpu>(new GrGLGpu(std::move(glContext), context));
- }
- GrGLGpu::GrGLGpu(std::unique_ptr<GrGLContext> ctx, GrContext* context)
- : GrGpu(context)
- , fGLContext(std::move(ctx))
- , fProgramCache(new ProgramCache(this))
- , fHWProgramID(0)
- , fTempSrcFBOID(0)
- , fTempDstFBOID(0)
- , fStencilClearFBOID(0) {
- SkASSERT(fGLContext);
- GrGLClearErr(this->glInterface());
- fCaps = sk_ref_sp(fGLContext->caps());
- fHWTextureUnitBindings.reset(this->numTextureUnits());
- this->hwBufferState(GrGpuBufferType::kVertex)->fGLTarget = GR_GL_ARRAY_BUFFER;
- this->hwBufferState(GrGpuBufferType::kIndex)->fGLTarget = GR_GL_ELEMENT_ARRAY_BUFFER;
- if (GrGLCaps::kChromium_TransferBufferType == this->glCaps().transferBufferType()) {
- this->hwBufferState(GrGpuBufferType::kXferCpuToGpu)->fGLTarget =
- GR_GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM;
- this->hwBufferState(GrGpuBufferType::kXferGpuToCpu)->fGLTarget =
- GR_GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM;
- } else {
- this->hwBufferState(GrGpuBufferType::kXferCpuToGpu)->fGLTarget = GR_GL_PIXEL_UNPACK_BUFFER;
- this->hwBufferState(GrGpuBufferType::kXferGpuToCpu)->fGLTarget = GR_GL_PIXEL_PACK_BUFFER;
- }
- for (int i = 0; i < kGrGpuBufferTypeCount; ++i) {
- fHWBufferState[i].invalidate();
- }
- GR_STATIC_ASSERT(4 == SK_ARRAY_COUNT(fHWBufferState));
- if (this->glCaps().shaderCaps()->pathRenderingSupport()) {
- fPathRendering.reset(new GrGLPathRendering(this));
- }
- if (this->glCaps().samplerObjectSupport()) {
- fSamplerObjectCache.reset(new SamplerObjectCache(this));
- }
- }
- GrGLGpu::~GrGLGpu() {
- // Ensure any GrGpuResource objects get deleted first, since they may require a working GrGLGpu
- // to release the resources held by the objects themselves.
- fPathRendering.reset();
- fCopyProgramArrayBuffer.reset();
- fMipmapProgramArrayBuffer.reset();
- fHWProgram.reset();
- if (fHWProgramID) {
- // detach the current program so there is no confusion on OpenGL's part
- // that we want it to be deleted
- GL_CALL(UseProgram(0));
- }
- if (fTempSrcFBOID) {
- this->deleteFramebuffer(fTempSrcFBOID);
- }
- if (fTempDstFBOID) {
- this->deleteFramebuffer(fTempDstFBOID);
- }
- if (fStencilClearFBOID) {
- this->deleteFramebuffer(fStencilClearFBOID);
- }
- for (size_t i = 0; i < SK_ARRAY_COUNT(fCopyPrograms); ++i) {
- if (0 != fCopyPrograms[i].fProgram) {
- GL_CALL(DeleteProgram(fCopyPrograms[i].fProgram));
- }
- }
- for (size_t i = 0; i < SK_ARRAY_COUNT(fMipmapPrograms); ++i) {
- if (0 != fMipmapPrograms[i].fProgram) {
- GL_CALL(DeleteProgram(fMipmapPrograms[i].fProgram));
- }
- }
- delete fProgramCache;
- fSamplerObjectCache.reset();
- }
- void GrGLGpu::disconnect(DisconnectType type) {
- INHERITED::disconnect(type);
- if (DisconnectType::kCleanup == type) {
- if (fHWProgramID) {
- GL_CALL(UseProgram(0));
- }
- if (fTempSrcFBOID) {
- this->deleteFramebuffer(fTempSrcFBOID);
- }
- if (fTempDstFBOID) {
- this->deleteFramebuffer(fTempDstFBOID);
- }
- if (fStencilClearFBOID) {
- this->deleteFramebuffer(fStencilClearFBOID);
- }
- for (size_t i = 0; i < SK_ARRAY_COUNT(fCopyPrograms); ++i) {
- if (fCopyPrograms[i].fProgram) {
- GL_CALL(DeleteProgram(fCopyPrograms[i].fProgram));
- }
- }
- for (size_t i = 0; i < SK_ARRAY_COUNT(fMipmapPrograms); ++i) {
- if (fMipmapPrograms[i].fProgram) {
- GL_CALL(DeleteProgram(fMipmapPrograms[i].fProgram));
- }
- }
- if (fSamplerObjectCache) {
- fSamplerObjectCache->release();
- }
- } else {
- if (fProgramCache) {
- fProgramCache->abandon();
- }
- if (fSamplerObjectCache) {
- fSamplerObjectCache->abandon();
- }
- }
- fHWProgram.reset();
- delete fProgramCache;
- fProgramCache = nullptr;
- fHWProgramID = 0;
- fTempSrcFBOID = 0;
- fTempDstFBOID = 0;
- fStencilClearFBOID = 0;
- fCopyProgramArrayBuffer.reset();
- for (size_t i = 0; i < SK_ARRAY_COUNT(fCopyPrograms); ++i) {
- fCopyPrograms[i].fProgram = 0;
- }
- fMipmapProgramArrayBuffer.reset();
- for (size_t i = 0; i < SK_ARRAY_COUNT(fMipmapPrograms); ++i) {
- fMipmapPrograms[i].fProgram = 0;
- }
- if (this->glCaps().shaderCaps()->pathRenderingSupport()) {
- this->glPathRendering()->disconnect(type);
- }
- }
- ///////////////////////////////////////////////////////////////////////////////
- void GrGLGpu::onResetContext(uint32_t resetBits) {
- if (resetBits & kMisc_GrGLBackendState) {
- // we don't use the zb at all
- GL_CALL(Disable(GR_GL_DEPTH_TEST));
- GL_CALL(DepthMask(GR_GL_FALSE));
- // We don't use face culling.
- GL_CALL(Disable(GR_GL_CULL_FACE));
- // We do use separate stencil. Our algorithms don't care which face is front vs. back so
- // just set this to the default for self-consistency.
- GL_CALL(FrontFace(GR_GL_CCW));
- this->hwBufferState(GrGpuBufferType::kXferCpuToGpu)->invalidate();
- this->hwBufferState(GrGpuBufferType::kXferGpuToCpu)->invalidate();
- if (GR_IS_GR_GL(this->glStandard())) {
- #ifndef USE_NSIGHT
- // Desktop-only state that we never change
- if (!this->glCaps().isCoreProfile()) {
- GL_CALL(Disable(GR_GL_POINT_SMOOTH));
- GL_CALL(Disable(GR_GL_LINE_SMOOTH));
- GL_CALL(Disable(GR_GL_POLYGON_SMOOTH));
- GL_CALL(Disable(GR_GL_POLYGON_STIPPLE));
- GL_CALL(Disable(GR_GL_COLOR_LOGIC_OP));
- GL_CALL(Disable(GR_GL_INDEX_LOGIC_OP));
- }
- // The windows NVIDIA driver has GL_ARB_imaging in the extension string when using a
- // core profile. This seems like a bug since the core spec removes any mention of
- // GL_ARB_imaging.
- if (this->glCaps().imagingSupport() && !this->glCaps().isCoreProfile()) {
- GL_CALL(Disable(GR_GL_COLOR_TABLE));
- }
- GL_CALL(Disable(GR_GL_POLYGON_OFFSET_FILL));
- if (this->caps()->wireframeMode()) {
- GL_CALL(PolygonMode(GR_GL_FRONT_AND_BACK, GR_GL_LINE));
- } else {
- GL_CALL(PolygonMode(GR_GL_FRONT_AND_BACK, GR_GL_FILL));
- }
- #endif
- // Since ES doesn't support glPointSize at all we always use the VS to
- // set the point size
- GL_CALL(Enable(GR_GL_VERTEX_PROGRAM_POINT_SIZE));
- }
- if (GR_IS_GR_GL_ES(this->glStandard()) &&
- this->glCaps().fbFetchRequiresEnablePerSample()) {
- // The arm extension requires specifically enabling MSAA fetching per sample.
- // On some devices this may have a perf hit. Also multiple render targets are disabled
- GL_CALL(Enable(GR_GL_FETCH_PER_SAMPLE));
- }
- fHWWriteToColor = kUnknown_TriState;
- // we only ever use lines in hairline mode
- GL_CALL(LineWidth(1));
- GL_CALL(Disable(GR_GL_DITHER));
- fHWClearColor[0] = fHWClearColor[1] = fHWClearColor[2] = fHWClearColor[3] = SK_FloatNaN;
- }
- if (resetBits & kMSAAEnable_GrGLBackendState) {
- fMSAAEnabled = kUnknown_TriState;
- if (this->caps()->mixedSamplesSupport()) {
- // The skia blend modes all use premultiplied alpha and therefore expect RGBA coverage
- // modulation. This state has no effect when not rendering to a mixed sampled target.
- GL_CALL(CoverageModulation(GR_GL_RGBA));
- }
- }
- fHWActiveTextureUnitIdx = -1; // invalid
- fLastPrimitiveType = static_cast<GrPrimitiveType>(-1);
- if (resetBits & kTextureBinding_GrGLBackendState) {
- for (int s = 0; s < this->numTextureUnits(); ++s) {
- fHWTextureUnitBindings[s].invalidateAllTargets(false);
- }
- if (fSamplerObjectCache) {
- fSamplerObjectCache->invalidateBindings();
- }
- }
- if (resetBits & kBlend_GrGLBackendState) {
- fHWBlendState.invalidate();
- }
- if (resetBits & kView_GrGLBackendState) {
- fHWScissorSettings.invalidate();
- fHWWindowRectsState.invalidate();
- fHWViewport.invalidate();
- }
- if (resetBits & kStencil_GrGLBackendState) {
- fHWStencilSettings.invalidate();
- fHWStencilTestEnabled = kUnknown_TriState;
- }
- // Vertex
- if (resetBits & kVertex_GrGLBackendState) {
- fHWVertexArrayState.invalidate();
- this->hwBufferState(GrGpuBufferType::kVertex)->invalidate();
- this->hwBufferState(GrGpuBufferType::kIndex)->invalidate();
- }
- if (resetBits & kRenderTarget_GrGLBackendState) {
- fHWBoundRenderTargetUniqueID.makeInvalid();
- fHWSRGBFramebuffer = kUnknown_TriState;
- }
- if (resetBits & kPathRendering_GrGLBackendState) {
- if (this->caps()->shaderCaps()->pathRenderingSupport()) {
- this->glPathRendering()->resetContext();
- }
- }
- // we assume these values
- if (resetBits & kPixelStore_GrGLBackendState) {
- if (this->caps()->writePixelsRowBytesSupport()) {
- GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
- }
- if (this->glCaps().readPixelsRowBytesSupport()) {
- GL_CALL(PixelStorei(GR_GL_PACK_ROW_LENGTH, 0));
- }
- if (this->glCaps().packFlipYSupport()) {
- GL_CALL(PixelStorei(GR_GL_PACK_REVERSE_ROW_ORDER, GR_GL_FALSE));
- }
- }
- if (resetBits & kProgram_GrGLBackendState) {
- fHWProgramID = 0;
- fHWProgram.reset();
- }
- ++fResetTimestampForTextureParameters;
- }
- static bool check_backend_texture(const GrBackendTexture& backendTex, const GrGLCaps& caps,
- GrGLTexture::IDDesc* idDesc) {
- GrGLTextureInfo info;
- if (!backendTex.getGLTextureInfo(&info) || !info.fID || !info.fFormat) {
- return false;
- }
- idDesc->fInfo = info;
- if (GR_GL_TEXTURE_EXTERNAL == idDesc->fInfo.fTarget) {
- if (!caps.shaderCaps()->externalTextureSupport()) {
- return false;
- }
- } else if (GR_GL_TEXTURE_RECTANGLE == idDesc->fInfo.fTarget) {
- if (!caps.rectangleTextureSupport()) {
- return false;
- }
- } else if (GR_GL_TEXTURE_2D != idDesc->fInfo.fTarget) {
- return false;
- }
- if (backendTex.isProtected()) {
- // Not supported in GL backend at this time.
- return false;
- }
- return true;
- }
- sk_sp<GrTexture> GrGLGpu::onWrapBackendTexture(const GrBackendTexture& backendTex,
- GrColorType grColorType, GrWrapOwnership ownership,
- GrWrapCacheable cacheable, GrIOType ioType) {
- GrGLTexture::IDDesc idDesc;
- if (!check_backend_texture(backendTex, this->glCaps(), &idDesc)) {
- return nullptr;
- }
- if (kBorrow_GrWrapOwnership == ownership) {
- idDesc.fOwnership = GrBackendObjectOwnership::kBorrowed;
- } else {
- idDesc.fOwnership = GrBackendObjectOwnership::kOwned;
- }
- GrPixelConfig config = this->caps()->getConfigFromBackendFormat(backendTex.getBackendFormat(),
- grColorType);
- SkASSERT(kUnknown_GrPixelConfig != config);
- GrSurfaceDesc surfDesc;
- surfDesc.fWidth = backendTex.width();
- surfDesc.fHeight = backendTex.height();
- surfDesc.fConfig = config;
- GrMipMapsStatus mipMapsStatus = backendTex.hasMipMaps() ? GrMipMapsStatus::kValid
- : GrMipMapsStatus::kNotAllocated;
- auto texture = GrGLTexture::MakeWrapped(this, surfDesc, mipMapsStatus, idDesc,
- backendTex.getGLTextureParams(), cacheable, ioType);
- // We don't know what parameters are already set on wrapped textures.
- texture->textureParamsModified();
- return std::move(texture);
- }
- sk_sp<GrTexture> GrGLGpu::onWrapRenderableBackendTexture(const GrBackendTexture& backendTex,
- int sampleCnt,
- GrColorType colorType,
- GrWrapOwnership ownership,
- GrWrapCacheable cacheable) {
- GrGLTexture::IDDesc idDesc;
- if (!check_backend_texture(backendTex, this->glCaps(), &idDesc)) {
- return nullptr;
- }
- // We don't support rendering to a EXTERNAL texture.
- if (GR_GL_TEXTURE_EXTERNAL == idDesc.fInfo.fTarget) {
- return nullptr;
- }
- if (kBorrow_GrWrapOwnership == ownership) {
- idDesc.fOwnership = GrBackendObjectOwnership::kBorrowed;
- } else {
- idDesc.fOwnership = GrBackendObjectOwnership::kOwned;
- }
- const GrCaps* caps = this->caps();
- GrPixelConfig config = caps->getConfigFromBackendFormat(backendTex.getBackendFormat(),
- colorType);
- SkASSERT(kUnknown_GrPixelConfig != config);
- GrSurfaceDesc surfDesc;
- surfDesc.fWidth = backendTex.width();
- surfDesc.fHeight = backendTex.height();
- surfDesc.fConfig = config;
- sampleCnt =
- caps->getRenderTargetSampleCount(sampleCnt, colorType, backendTex.getBackendFormat());
- if (sampleCnt < 1) {
- return nullptr;
- }
- GrGLRenderTarget::IDDesc rtIDDesc;
- if (!this->createRenderTargetObjects(surfDesc, sampleCnt, idDesc.fInfo, &rtIDDesc)) {
- return nullptr;
- }
- GrMipMapsStatus mipMapsStatus = backendTex.hasMipMaps() ? GrMipMapsStatus::kDirty
- : GrMipMapsStatus::kNotAllocated;
- sk_sp<GrGLTextureRenderTarget> texRT(GrGLTextureRenderTarget::MakeWrapped(
- this, surfDesc, sampleCnt, idDesc, backendTex.getGLTextureParams(), rtIDDesc, cacheable,
- mipMapsStatus));
- texRT->baseLevelWasBoundToFBO();
- // We don't know what parameters are already set on wrapped textures.
- texRT->textureParamsModified();
- return std::move(texRT);
- }
- sk_sp<GrRenderTarget> GrGLGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& backendRT,
- GrColorType grColorType) {
- GrGLFramebufferInfo info;
- if (!backendRT.getGLFramebufferInfo(&info)) {
- return nullptr;
- }
- if (backendRT.isProtected()) {
- // Not supported in GL at this time.
- return nullptr;
- }
- GrGLRenderTarget::IDDesc idDesc;
- idDesc.fRTFBOID = info.fFBOID;
- idDesc.fMSColorRenderbufferID = 0;
- idDesc.fTexFBOID = GrGLRenderTarget::kUnresolvableFBOID;
- idDesc.fRTFBOOwnership = GrBackendObjectOwnership::kBorrowed;
- GrPixelConfig config = this->caps()->getConfigFromBackendFormat(backendRT.getBackendFormat(),
- grColorType);
- SkASSERT(kUnknown_GrPixelConfig != config);
- GrSurfaceDesc desc;
- desc.fWidth = backendRT.width();
- desc.fHeight = backendRT.height();
- desc.fConfig = config;
- int sampleCount =
- this->caps()->getRenderTargetSampleCount(backendRT.sampleCnt(), grColorType,
- backendRT.getBackendFormat());
- return GrGLRenderTarget::MakeWrapped(this, desc, sampleCount, info.fFormat, idDesc,
- backendRT.stencilBits());
- }
- sk_sp<GrRenderTarget> GrGLGpu::onWrapBackendTextureAsRenderTarget(const GrBackendTexture& tex,
- int sampleCnt,
- GrColorType grColorType) {
- GrGLTextureInfo info;
- if (!tex.getGLTextureInfo(&info) || !info.fID) {
- return nullptr;
- }
- if (GR_GL_TEXTURE_RECTANGLE != info.fTarget &&
- GR_GL_TEXTURE_2D != info.fTarget) {
- // Only texture rectangle and texture 2d are supported. We do not check whether texture
- // rectangle is supported by Skia - if the caller provided us with a texture rectangle,
- // we assume the necessary support exists.
- return nullptr;
- }
- GrPixelConfig config = this->caps()->getConfigFromBackendFormat(tex.getBackendFormat(),
- grColorType);
- SkASSERT(kUnknown_GrPixelConfig != config);
- GrSurfaceDesc surfDesc;
- surfDesc.fWidth = tex.width();
- surfDesc.fHeight = tex.height();
- surfDesc.fConfig = config;
- int sampleCount = this->caps()->getRenderTargetSampleCount(sampleCnt, grColorType,
- tex.getBackendFormat());
- GrGLRenderTarget::IDDesc rtIDDesc;
- if (!this->createRenderTargetObjects(surfDesc, sampleCount, info, &rtIDDesc)) {
- return nullptr;
- }
- return GrGLRenderTarget::MakeWrapped(this, surfDesc, sampleCount, info.fFormat, rtIDDesc, 0);
- }
- static bool check_write_and_transfer_input(GrGLTexture* glTex) {
- if (!glTex) {
- return false;
- }
- // Write or transfer of pixels is not implemented for TEXTURE_EXTERNAL textures
- if (GR_GL_TEXTURE_EXTERNAL == glTex->target()) {
- return false;
- }
- return true;
- }
- bool GrGLGpu::onWritePixels(GrSurface* surface, int left, int top, int width, int height,
- GrColorType srcColorType, const GrMipLevel texels[],
- int mipLevelCount) {
- auto glTex = static_cast<GrGLTexture*>(surface->asTexture());
- if (!check_write_and_transfer_input(glTex)) {
- return false;
- }
- this->bindTextureToScratchUnit(glTex->target(), glTex->textureID());
- // No sRGB transformation occurs in uploadTexData. We choose to make the src config match the
- // srgb-ness of the surface to avoid issues in ES2 where internal/external formats must match.
- // When we're on ES2 and the dst is GL_SRGB_ALPHA by making the config be kSRGB_8888 we know
- // that our caps will choose GL_SRGB_ALPHA as the external format, too. On ES3 or regular GL our
- // caps knows to make the external format be GL_RGBA.
- auto srcAsConfig = GrColorTypeToPixelConfig(srcColorType);
- SkASSERT(!GrPixelConfigIsCompressed(glTex->config()));
- return this->uploadTexData(glTex->config(), glTex->width(), glTex->height(), glTex->target(),
- kWrite_UploadType, left, top, width, height, srcAsConfig, texels,
- mipLevelCount);
- }
- // For GL_[UN]PACK_ALIGNMENT. TODO: This really wants to be GrColorType.
- static inline GrGLint config_alignment(GrPixelConfig config) {
- SkASSERT(!GrPixelConfigIsCompressed(config));
- switch (config) {
- case kAlpha_8_GrPixelConfig:
- case kAlpha_8_as_Alpha_GrPixelConfig:
- case kAlpha_8_as_Red_GrPixelConfig:
- case kGray_8_GrPixelConfig:
- case kGray_8_as_Lum_GrPixelConfig:
- case kGray_8_as_Red_GrPixelConfig:
- return 1;
- case kRGB_565_GrPixelConfig:
- case kRGBA_4444_GrPixelConfig:
- case kRG_88_GrPixelConfig:
- case kAlpha_half_GrPixelConfig:
- case kAlpha_half_as_Lum_GrPixelConfig:
- case kAlpha_half_as_Red_GrPixelConfig:
- case kRGBA_half_GrPixelConfig:
- case kRGBA_half_Clamped_GrPixelConfig:
- case kR_16_GrPixelConfig:
- return 2;
- case kRGBA_8888_GrPixelConfig:
- case kRGB_888_GrPixelConfig: // We're really talking about GrColorType::kRGB_888x here.
- case kRGB_888X_GrPixelConfig:
- case kBGRA_8888_GrPixelConfig:
- case kSRGBA_8888_GrPixelConfig:
- case kRGBA_1010102_GrPixelConfig:
- case kRGBA_float_GrPixelConfig:
- case kRG_1616_GrPixelConfig:
- return 4;
- case kRGB_ETC1_GrPixelConfig:
- case kUnknown_GrPixelConfig:
- return 0;
- // Experimental (for Y416 and mutant P016/P010)
- case kRGBA_16161616_GrPixelConfig:
- return 8;
- case kRG_half_GrPixelConfig:
- return 4;
- }
- SK_ABORT("Invalid pixel config");
- return 0;
- }
- bool GrGLGpu::onTransferPixelsTo(GrTexture* texture, int left, int top, int width, int height,
- GrColorType bufferColorType, GrGpuBuffer* transferBuffer,
- size_t offset, size_t rowBytes) {
- GrGLTexture* glTex = static_cast<GrGLTexture*>(texture);
- GrPixelConfig texConfig = glTex->config();
- SkASSERT(this->caps()->isConfigTexturable(texConfig));
- // Can't transfer compressed data
- SkASSERT(!GrPixelConfigIsCompressed(glTex->config()));
- if (!check_write_and_transfer_input(glTex)) {
- return false;
- }
- static_assert(sizeof(int) == sizeof(int32_t), "");
- if (width <= 0 || height <= 0) {
- return false;
- }
- this->bindTextureToScratchUnit(glTex->target(), glTex->textureID());
- SkASSERT(!transferBuffer->isMapped());
- SkASSERT(!transferBuffer->isCpuBuffer());
- const GrGLBuffer* glBuffer = static_cast<const GrGLBuffer*>(transferBuffer);
- this->bindBuffer(GrGpuBufferType::kXferCpuToGpu, glBuffer);
- SkDEBUGCODE(
- SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
- SkIRect bounds = SkIRect::MakeWH(texture->width(), texture->height());
- SkASSERT(bounds.contains(subRect));
- )
- int bpp = GrColorTypeBytesPerPixel(bufferColorType);
- const size_t trimRowBytes = width * bpp;
- const void* pixels = (void*)offset;
- if (width < 0 || height < 0) {
- return false;
- }
- bool restoreGLRowLength = false;
- if (trimRowBytes != rowBytes) {
- // we should have checked for this support already
- SkASSERT(this->glCaps().writePixelsRowBytesSupport());
- GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, rowBytes / bpp));
- restoreGLRowLength = true;
- }
- // Internal format comes from the texture desc.
- GrGLenum internalFormat;
- // External format and type come from the upload data.
- GrGLenum externalFormat;
- GrGLenum externalType;
- auto bufferAsConfig = GrColorTypeToPixelConfig(bufferColorType);
- if (!this->glCaps().getTexImageFormats(texConfig, bufferAsConfig, &internalFormat,
- &externalFormat, &externalType)) {
- return false;
- }
- GL_CALL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, config_alignment(texConfig)));
- GL_CALL(TexSubImage2D(glTex->target(),
- 0,
- left, top,
- width,
- height,
- externalFormat, externalType,
- pixels));
- if (restoreGLRowLength) {
- GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
- }
- return true;
- }
- bool GrGLGpu::onTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
- GrColorType dstColorType, GrGpuBuffer* transferBuffer,
- size_t offset) {
- auto* glBuffer = static_cast<GrGLBuffer*>(transferBuffer);
- this->bindBuffer(GrGpuBufferType::kXferGpuToCpu, glBuffer);
- auto offsetAsPtr = reinterpret_cast<void*>(offset);
- return this->readOrTransferPixelsFrom(surface, left, top, width, height, dstColorType,
- offsetAsPtr, width);
- }
- /**
- * Creates storage space for the texture and fills it with texels.
- *
- * @param config Pixel config of the texture.
- * @param interface The GL interface in use.
- * @param caps The capabilities of the GL device.
- * @param target Which bound texture to target (GR_GL_TEXTURE_2D, e.g.)
- * @param internalFormat The data format used for the internal storage of the texture. May be sized.
- * @param internalFormatForTexStorage The data format used for the TexStorage API. Must be sized.
- * @param externalFormat The data format used for the external storage of the texture.
- * @param externalType The type of the data used for the external storage of the texture.
- * @param texels The texel data of the texture being created.
- * @param mipLevelCount Number of mipmap levels
- * @param baseWidth The width of the texture's base mipmap level
- * @param baseHeight The height of the texture's base mipmap level
- */
- static bool allocate_and_populate_texture(GrPixelConfig config,
- const GrGLInterface& interface,
- const GrGLCaps& caps,
- GrGLenum target,
- GrGLenum internalFormat,
- GrGLenum internalFormatForTexStorage,
- GrGLenum externalFormat,
- GrGLenum externalType,
- const GrMipLevel texels[],
- int mipLevelCount,
- int baseWidth,
- int baseHeight,
- bool* changedUnpackRowLength) {
- CLEAR_ERROR_BEFORE_ALLOC(&interface);
- if (caps.configSupportsTexStorage(config)) {
- // We never resize or change formats of textures.
- GL_ALLOC_CALL(&interface,
- TexStorage2D(target, SkTMax(mipLevelCount, 1), internalFormatForTexStorage,
- baseWidth, baseHeight));
- GrGLenum error = CHECK_ALLOC_ERROR(&interface);
- if (error != GR_GL_NO_ERROR) {
- return false;
- } else {
- size_t bpp = GrBytesPerPixel(config);
- for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
- const void* currentMipData = texels[currentMipLevel].fPixels;
- if (currentMipData == nullptr) {
- continue;
- }
- int twoToTheMipLevel = 1 << currentMipLevel;
- const int currentWidth = SkTMax(1, baseWidth / twoToTheMipLevel);
- const int currentHeight = SkTMax(1, baseHeight / twoToTheMipLevel);
- if (texels[currentMipLevel].fPixels) {
- const size_t trimRowBytes = currentWidth * bpp;
- const size_t rowBytes = texels[currentMipLevel].fRowBytes;
- if (rowBytes != trimRowBytes) {
- SkASSERT(caps.writePixelsRowBytesSupport());
- GrGLint rowLength = static_cast<GrGLint>(rowBytes / bpp);
- GR_GL_CALL(&interface, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, rowLength));
- *changedUnpackRowLength = true;
- } else if (*changedUnpackRowLength) {
- SkASSERT(caps.writePixelsRowBytesSupport());
- GR_GL_CALL(&interface, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
- *changedUnpackRowLength = false;
- }
- }
- GR_GL_CALL(&interface,
- TexSubImage2D(target,
- currentMipLevel,
- 0, // left
- 0, // top
- currentWidth,
- currentHeight,
- externalFormat, externalType,
- currentMipData));
- }
- return true;
- }
- } else {
- if (!mipLevelCount) {
- GL_ALLOC_CALL(&interface,
- TexImage2D(target,
- 0,
- internalFormat,
- baseWidth,
- baseHeight,
- 0, // border
- externalFormat, externalType,
- nullptr));
- GrGLenum error = CHECK_ALLOC_ERROR(&interface);
- if (error != GR_GL_NO_ERROR) {
- return false;
- }
- } else {
- size_t bpp = GrBytesPerPixel(config);
- for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
- int twoToTheMipLevel = 1 << currentMipLevel;
- const int currentWidth = SkTMax(1, baseWidth / twoToTheMipLevel);
- const int currentHeight = SkTMax(1, baseHeight / twoToTheMipLevel);
- if (texels[currentMipLevel].fPixels) {
- const size_t trimRowBytes = currentWidth * bpp;
- const size_t rowBytes = texels[currentMipLevel].fRowBytes;
- if (rowBytes != trimRowBytes) {
- SkASSERT(caps.writePixelsRowBytesSupport());
- GrGLint rowLength = static_cast<GrGLint>(rowBytes / bpp);
- GR_GL_CALL(&interface, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, rowLength));
- *changedUnpackRowLength = true;
- } else if (*changedUnpackRowLength) {
- SkASSERT(caps.writePixelsRowBytesSupport());
- GR_GL_CALL(&interface, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
- *changedUnpackRowLength = false;
- }
- }
- const void* currentMipData = texels[currentMipLevel].fPixels;
- // Even if curremtMipData is nullptr, continue to call TexImage2D.
- // This will allocate texture memory which we can later populate.
- GL_ALLOC_CALL(&interface,
- TexImage2D(target,
- currentMipLevel,
- internalFormat,
- currentWidth,
- currentHeight,
- 0, // border
- externalFormat, externalType,
- currentMipData));
- GrGLenum error = CHECK_ALLOC_ERROR(&interface);
- if (error != GR_GL_NO_ERROR) {
- return false;
- }
- }
- }
- }
- return true;
- }
- /**
- * After a texture is created, any state which was altered during its creation
- * needs to be restored.
- *
- * @param interface The GL interface to use.
- * @param caps The capabilities of the GL device.
- * @param restoreGLRowLength Should the row length unpacking be restored?
- * @param glFlipY Did GL flip the texture vertically?
- */
- static void restore_pixelstore_state(const GrGLInterface& interface, const GrGLCaps& caps,
- bool restoreGLRowLength) {
- if (restoreGLRowLength) {
- SkASSERT(caps.writePixelsRowBytesSupport());
- GR_GL_CALL(&interface, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
- }
- }
- void GrGLGpu::unbindCpuToGpuXferBuffer() {
- auto* xferBufferState = this->hwBufferState(GrGpuBufferType::kXferCpuToGpu);
- if (!xferBufferState->fBoundBufferUniqueID.isInvalid()) {
- GL_CALL(BindBuffer(xferBufferState->fGLTarget, 0));
- xferBufferState->invalidate();
- }
- }
- // TODO: Make this take a GrColorType instead of dataConfig. This requires updating GrGLCaps to
- // convert from GrColorType to externalFormat/externalType GLenum values.
- bool GrGLGpu::uploadTexData(GrPixelConfig texConfig, int texWidth, int texHeight, GrGLenum target,
- UploadType uploadType, int left, int top, int width, int height,
- GrPixelConfig dataConfig, const GrMipLevel texels[], int mipLevelCount,
- GrMipMapsStatus* mipMapsStatus) {
- // If we're uploading compressed data then we should be using uploadCompressedTexData
- SkASSERT(!GrPixelConfigIsCompressed(dataConfig));
- SkASSERT(this->caps()->isConfigTexturable(texConfig));
- SkDEBUGCODE(
- SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
- SkIRect bounds = SkIRect::MakeWH(texWidth, texHeight);
- SkASSERT(bounds.contains(subRect));
- )
- SkASSERT(1 == mipLevelCount ||
- (0 == left && 0 == top && width == texWidth && height == texHeight));
- this->unbindCpuToGpuXferBuffer();
- const GrGLInterface* interface = this->glInterface();
- const GrGLCaps& caps = this->glCaps();
- size_t bpp = GrBytesPerPixel(dataConfig);
- if (width == 0 || height == 0) {
- return false;
- }
- // Internal format comes from the texture desc.
- GrGLenum internalFormat;
- // External format and type come from the upload data.
- GrGLenum externalFormat;
- GrGLenum externalType;
- if (!this->glCaps().getTexImageFormats(texConfig, dataConfig, &internalFormat, &externalFormat,
- &externalType)) {
- return false;
- }
- // TexStorage requires a sized format, and internalFormat may or may not be
- GrGLenum internalFormatForTexStorage = this->glCaps().configSizedInternalFormat(texConfig);
- /*
- * Check whether to allocate a temporary buffer for flipping y or
- * because our srcData has extra bytes past each row. If so, we need
- * to trim those off here, since GL ES may not let us specify
- * GL_UNPACK_ROW_LENGTH.
- */
- bool restoreGLRowLength = false;
- // in case we need a temporary, trimmed copy of the src pixels
- SkAutoSMalloc<128 * 128> tempStorage;
- if (mipMapsStatus) {
- *mipMapsStatus = GrMipMapsStatus::kValid;
- }
- if (mipMapsStatus && mipLevelCount <= 1) {
- *mipMapsStatus = GrMipMapsStatus::kNotAllocated;
- }
- if (mipLevelCount) {
- GR_GL_CALL(interface, PixelStorei(GR_GL_UNPACK_ALIGNMENT, config_alignment(texConfig)));
- }
- bool succeeded = true;
- if (kNewTexture_UploadType == uploadType) {
- if (0 == left && 0 == top && texWidth == width && texHeight == height) {
- succeeded = allocate_and_populate_texture(
- texConfig, *interface, caps, target, internalFormat,
- internalFormatForTexStorage, externalFormat, externalType, texels,
- mipLevelCount, width, height, &restoreGLRowLength);
- } else {
- succeeded = false;
- }
- } else {
- for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
- if (!texels[currentMipLevel].fPixels) {
- continue;
- }
- int twoToTheMipLevel = 1 << currentMipLevel;
- const int currentWidth = SkTMax(1, width / twoToTheMipLevel);
- const int currentHeight = SkTMax(1, height / twoToTheMipLevel);
- const size_t trimRowBytes = currentWidth * bpp;
- const size_t rowBytes = texels[currentMipLevel].fRowBytes;
- if (caps.writePixelsRowBytesSupport() && rowBytes != trimRowBytes) {
- GrGLint rowLength = static_cast<GrGLint>(rowBytes / bpp);
- GR_GL_CALL(interface, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, rowLength));
- restoreGLRowLength = true;
- }
- GL_CALL(TexSubImage2D(target,
- currentMipLevel,
- left, top,
- currentWidth,
- currentHeight,
- externalFormat, externalType,
- texels[currentMipLevel].fPixels));
- }
- }
- restore_pixelstore_state(*interface, caps, restoreGLRowLength);
- return succeeded;
- }
- GrGLenum GrGLGpu::uploadCompressedTexData(SkImage::CompressionType compressionType, int width,
- int height, GrGLenum target, const void* data) {
- const GrGLCaps& caps = this->glCaps();
- GrPixelConfig config = GrCompressionTypePixelConfig(compressionType);
- // We only need the internal format for compressed 2D textures.
- GrGLenum internalFormat;
- if (!caps.getCompressedTexImageFormats(config, &internalFormat)) {
- return 0;
- }
- bool useTexStorage = caps.configSupportsTexStorage(config);
- static constexpr int kMipLevelCount = 1;
- // Make sure that the width and height that we pass to OpenGL
- // is a multiple of the block size.
- size_t dataSize = GrCompressedDataSize(compressionType, width, height);
- if (useTexStorage) {
- // We never resize or change formats of textures.
- GL_ALLOC_CALL(this->glInterface(),
- TexStorage2D(target, kMipLevelCount, internalFormat, width, height));
- GrGLenum error = CHECK_ALLOC_ERROR(this->glInterface());
- if (error != GR_GL_NO_ERROR) {
- return 0;
- }
- GL_CALL(CompressedTexSubImage2D(target,
- 0, // level
- 0, // left
- 0, // top
- width,
- height,
- internalFormat,
- SkToInt(dataSize),
- data));
- } else {
- GL_ALLOC_CALL(this->glInterface(), CompressedTexImage2D(target,
- 0, // level
- internalFormat,
- width,
- height,
- 0, // border
- SkToInt(dataSize),
- data));
- GrGLenum error = CHECK_ALLOC_ERROR(this->glInterface());
- if (error != GR_GL_NO_ERROR) {
- return 0;
- }
- }
- return internalFormat;
- }
- static bool renderbuffer_storage_msaa(const GrGLContext& ctx,
- int sampleCount,
- GrGLenum format,
- int width, int height) {
- CLEAR_ERROR_BEFORE_ALLOC(ctx.interface());
- SkASSERT(GrGLCaps::kNone_MSFBOType != ctx.caps()->msFBOType());
- switch (ctx.caps()->msFBOType()) {
- case GrGLCaps::kStandard_MSFBOType:
- GL_ALLOC_CALL(ctx.interface(),
- RenderbufferStorageMultisample(GR_GL_RENDERBUFFER,
- sampleCount,
- format,
- width, height));
- break;
- case GrGLCaps::kES_Apple_MSFBOType:
- GL_ALLOC_CALL(ctx.interface(),
- RenderbufferStorageMultisampleES2APPLE(GR_GL_RENDERBUFFER,
- sampleCount,
- format,
- width, height));
- break;
- case GrGLCaps::kES_EXT_MsToTexture_MSFBOType:
- case GrGLCaps::kES_IMG_MsToTexture_MSFBOType:
- GL_ALLOC_CALL(ctx.interface(),
- RenderbufferStorageMultisampleES2EXT(GR_GL_RENDERBUFFER,
- sampleCount,
- format,
- width, height));
- break;
- case GrGLCaps::kNone_MSFBOType:
- SK_ABORT("Shouldn't be here if we don't support multisampled renderbuffers.");
- break;
- }
- return (GR_GL_NO_ERROR == CHECK_ALLOC_ERROR(ctx.interface()));
- }
- bool GrGLGpu::createRenderTargetObjects(const GrSurfaceDesc& desc,
- int sampleCount,
- const GrGLTextureInfo& texInfo,
- GrGLRenderTarget::IDDesc* idDesc) {
- idDesc->fMSColorRenderbufferID = 0;
- idDesc->fRTFBOID = 0;
- idDesc->fRTFBOOwnership = GrBackendObjectOwnership::kOwned;
- idDesc->fTexFBOID = 0;
- GrGLenum status;
- GrGLenum colorRenderbufferFormat = 0; // suppress warning
- GrGLFormat format = GrGLFormatFromGLEnum(texInfo.fFormat);
- if (format == GrGLFormat::kUnknown) {
- goto FAILED;
- }
- if (sampleCount > 1 && GrGLCaps::kNone_MSFBOType == this->glCaps().msFBOType()) {
- goto FAILED;
- }
- GL_CALL(GenFramebuffers(1, &idDesc->fTexFBOID));
- if (!idDesc->fTexFBOID) {
- goto FAILED;
- }
- // If we are using multisampling we will create two FBOS. We render to one and then resolve to
- // the texture bound to the other. The exception is the IMG multisample extension. With this
- // extension the texture is multisampled when rendered to and then auto-resolves it when it is
- // rendered from.
- if (sampleCount > 1 && this->glCaps().usesMSAARenderBuffers()) {
- GL_CALL(GenFramebuffers(1, &idDesc->fRTFBOID));
- GL_CALL(GenRenderbuffers(1, &idDesc->fMSColorRenderbufferID));
- if (!idDesc->fRTFBOID ||
- !idDesc->fMSColorRenderbufferID) {
- goto FAILED;
- }
- colorRenderbufferFormat = this->glCaps().getRenderbufferInternalFormat(format);
- } else {
- idDesc->fRTFBOID = idDesc->fTexFBOID;
- }
- // below here we may bind the FBO
- fHWBoundRenderTargetUniqueID.makeInvalid();
- if (idDesc->fRTFBOID != idDesc->fTexFBOID) {
- SkASSERT(sampleCount > 1);
- GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, idDesc->fMSColorRenderbufferID));
- if (!renderbuffer_storage_msaa(*fGLContext, sampleCount, colorRenderbufferFormat,
- desc.fWidth, desc.fHeight)) {
- goto FAILED;
- }
- this->bindFramebuffer(GR_GL_FRAMEBUFFER, idDesc->fRTFBOID);
- GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
- GR_GL_COLOR_ATTACHMENT0,
- GR_GL_RENDERBUFFER,
- idDesc->fMSColorRenderbufferID));
- if (!this->glCaps().isFormatVerifiedColorAttachment(format)) {
- GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
- if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
- goto FAILED;
- }
- fGLContext->caps()->markFormatAsValidColorAttachment(format);
- }
- }
- this->bindFramebuffer(GR_GL_FRAMEBUFFER, idDesc->fTexFBOID);
- if (this->glCaps().usesImplicitMSAAResolve() && sampleCount > 1) {
- GL_CALL(FramebufferTexture2DMultisample(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0,
- texInfo.fTarget, texInfo.fID, 0, sampleCount));
- } else {
- GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER,
- GR_GL_COLOR_ATTACHMENT0,
- texInfo.fTarget,
- texInfo.fID, 0));
- }
- if (!this->glCaps().isFormatVerifiedColorAttachment(format)) {
- GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
- if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
- goto FAILED;
- }
- fGLContext->caps()->markFormatAsValidColorAttachment(format);
- }
- return true;
- FAILED:
- if (idDesc->fMSColorRenderbufferID) {
- GL_CALL(DeleteRenderbuffers(1, &idDesc->fMSColorRenderbufferID));
- }
- if (idDesc->fRTFBOID != idDesc->fTexFBOID) {
- this->deleteFramebuffer(idDesc->fRTFBOID);
- }
- if (idDesc->fTexFBOID) {
- this->deleteFramebuffer(idDesc->fTexFBOID);
- }
- return false;
- }
- // good to set a break-point here to know when createTexture fails
- static sk_sp<GrTexture> return_null_texture() {
- // SkDEBUGFAIL("null texture");
- return nullptr;
- }
- static GrGLTextureParameters::SamplerOverriddenState set_initial_texture_params(
- const GrGLInterface* interface, const GrGLTextureInfo& info) {
- // Some drivers like to know filter/wrap before seeing glTexImage2D. Some
- // drivers have a bug where an FBO won't be complete if it includes a
- // texture that is not mipmap complete (considering the filter in use).
- GrGLTextureParameters::SamplerOverriddenState state;
- state.fMinFilter = GR_GL_NEAREST;
- state.fMagFilter = GR_GL_NEAREST;
- state.fWrapS = GR_GL_CLAMP_TO_EDGE;
- state.fWrapT = GR_GL_CLAMP_TO_EDGE;
- GR_GL_CALL(interface, TexParameteri(info.fTarget, GR_GL_TEXTURE_MAG_FILTER, state.fMagFilter));
- GR_GL_CALL(interface, TexParameteri(info.fTarget, GR_GL_TEXTURE_MIN_FILTER, state.fMinFilter));
- GR_GL_CALL(interface, TexParameteri(info.fTarget, GR_GL_TEXTURE_WRAP_S, state.fWrapS));
- GR_GL_CALL(interface, TexParameteri(info.fTarget, GR_GL_TEXTURE_WRAP_T, state.fWrapT));
- return state;
- }
- sk_sp<GrTexture> GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc,
- GrRenderable renderable,
- int renderTargetSampleCnt,
- SkBudgeted budgeted,
- GrProtected isProtected,
- const GrMipLevel texels[],
- int mipLevelCount) {
- // We don't support protected textures in GL.
- if (isProtected == GrProtected::kYes) {
- return nullptr;
- }
- SkASSERT(GrGLCaps::kNone_MSFBOType != this->glCaps().msFBOType() || renderTargetSampleCnt == 1);
- GrGLTexture::IDDesc idDesc;
- idDesc.fOwnership = GrBackendObjectOwnership::kOwned;
- GrMipMapsStatus mipMapsStatus;
- GrGLTextureParameters::SamplerOverriddenState initialState;
- if (!this->createTextureImpl(desc, &idDesc.fInfo, renderable, &initialState, texels,
- mipLevelCount, &mipMapsStatus)) {
- return return_null_texture();
- }
- sk_sp<GrGLTexture> tex;
- if (renderable == GrRenderable::kYes) {
- // unbind the texture from the texture unit before binding it to the frame buffer
- GL_CALL(BindTexture(idDesc.fInfo.fTarget, 0));
- GrGLRenderTarget::IDDesc rtIDDesc;
- if (!this->createRenderTargetObjects(desc, renderTargetSampleCnt, idDesc.fInfo,
- &rtIDDesc)) {
- GL_CALL(DeleteTextures(1, &idDesc.fInfo.fID));
- return return_null_texture();
- }
- tex = sk_make_sp<GrGLTextureRenderTarget>(this, budgeted, desc, renderTargetSampleCnt,
- idDesc, rtIDDesc, mipMapsStatus);
- tex->baseLevelWasBoundToFBO();
- } else {
- tex = sk_make_sp<GrGLTexture>(this, budgeted, desc, idDesc, mipMapsStatus);
- }
- // The non-sampler params are still at their default values.
- tex->parameters()->set(&initialState, GrGLTextureParameters::NonsamplerState(),
- fResetTimestampForTextureParameters);
- bool clearLevelsWithoutData =
- this->caps()->shouldInitializeTextures() && this->glCaps().clearTextureSupport();
- if (clearLevelsWithoutData) {
- static constexpr uint32_t kZero = 0;
- int levelCnt = SkTMax(1, tex->texturePriv().maxMipMapLevel());
- for (int i = 0; i < levelCnt; ++i) {
- if (i >= mipLevelCount || !texels[i].fPixels) {
- GL_CALL(ClearTexImage(tex->textureID(), i, GR_GL_RGBA, GR_GL_UNSIGNED_BYTE,
- &kZero));
- }
- }
- }
- return std::move(tex);
- }
- sk_sp<GrTexture> GrGLGpu::onCreateCompressedTexture(int width, int height,
- SkImage::CompressionType compression,
- SkBudgeted budgeted, const void* data) {
- GrGLTexture::IDDesc idDesc;
- GrGLTextureParameters::SamplerOverriddenState initialState;
- if (!this->createCompressedTextureImpl(&idDesc.fInfo, width, height, compression, &initialState,
- data)) {
- return nullptr;
- }
- idDesc.fOwnership = GrBackendObjectOwnership::kOwned;
- GrSurfaceDesc desc;
- desc.fConfig = GrCompressionTypePixelConfig(compression);
- desc.fWidth = width;
- desc.fHeight = height;
- auto tex =
- sk_make_sp<GrGLTexture>(this, budgeted, desc, idDesc, GrMipMapsStatus::kNotAllocated);
- // The non-sampler params are still at their default values.
- tex->parameters()->set(&initialState, GrGLTextureParameters::NonsamplerState(),
- fResetTimestampForTextureParameters);
- return std::move(tex);
- }
- namespace {
- const GrGLuint kUnknownBitCount = GrGLStencilAttachment::kUnknownBitCount;
- void inline get_stencil_rb_sizes(const GrGLInterface* gl,
- GrGLStencilAttachment::Format* format) {
- // we shouldn't ever know one size and not the other
- SkASSERT((kUnknownBitCount == format->fStencilBits) ==
- (kUnknownBitCount == format->fTotalBits));
- if (kUnknownBitCount == format->fStencilBits) {
- GR_GL_GetRenderbufferParameteriv(gl, GR_GL_RENDERBUFFER,
- GR_GL_RENDERBUFFER_STENCIL_SIZE,
- (GrGLint*)&format->fStencilBits);
- if (format->fPacked) {
- GR_GL_GetRenderbufferParameteriv(gl, GR_GL_RENDERBUFFER,
- GR_GL_RENDERBUFFER_DEPTH_SIZE,
- (GrGLint*)&format->fTotalBits);
- format->fTotalBits += format->fStencilBits;
- } else {
- format->fTotalBits = format->fStencilBits;
- }
- }
- }
- }
- int GrGLGpu::getCompatibleStencilIndex(GrGLFormat format) {
- static const int kSize = 16;
- SkASSERT(this->glCaps().canFormatBeFBOColorAttachment(format));
- if (!this->glCaps().hasStencilFormatBeenDeterminedForFormat(format)) {
- // Default to unsupported, set this if we find a stencil format that works.
- int firstWorkingStencilFormatIndex = -1;
- // Create color texture
- GrGLuint colorID = 0;
- GL_CALL(GenTextures(1, &colorID));
- this->bindTextureToScratchUnit(GR_GL_TEXTURE_2D, colorID);
- GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
- GR_GL_TEXTURE_MAG_FILTER,
- GR_GL_NEAREST));
- GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
- GR_GL_TEXTURE_MIN_FILTER,
- GR_GL_NEAREST));
- GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
- GR_GL_TEXTURE_WRAP_S,
- GR_GL_CLAMP_TO_EDGE));
- GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
- GR_GL_TEXTURE_WRAP_T,
- GR_GL_CLAMP_TO_EDGE));
- GrGLenum internalFormat = this->glCaps().getTexImageInternalFormat(format);
- GrGLenum externalFormat = this->glCaps().getBaseInternalFormat(format);
- GrGLenum externalType = this->glCaps().getFormatDefaultExternalType(format);
- if (!internalFormat || !externalFormat || !externalType) {
- return -1;
- }
- this->unbindCpuToGpuXferBuffer();
- CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
- GL_ALLOC_CALL(this->glInterface(), TexImage2D(GR_GL_TEXTURE_2D,
- 0,
- internalFormat,
- kSize,
- kSize,
- 0,
- externalFormat,
- externalType,
- nullptr));
- if (GR_GL_NO_ERROR != CHECK_ALLOC_ERROR(this->glInterface())) {
- GL_CALL(DeleteTextures(1, &colorID));
- return -1;
- }
- // unbind the texture from the texture unit before binding it to the frame buffer
- GL_CALL(BindTexture(GR_GL_TEXTURE_2D, 0));
- // Create Framebuffer
- GrGLuint fb = 0;
- GL_CALL(GenFramebuffers(1, &fb));
- this->bindFramebuffer(GR_GL_FRAMEBUFFER, fb);
- fHWBoundRenderTargetUniqueID.makeInvalid();
- GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER,
- GR_GL_COLOR_ATTACHMENT0,
- GR_GL_TEXTURE_2D,
- colorID,
- 0));
- GrGLuint sbRBID = 0;
- GL_CALL(GenRenderbuffers(1, &sbRBID));
- // look over formats till I find a compatible one
- int stencilFmtCnt = this->glCaps().stencilFormats().count();
- if (sbRBID) {
- GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, sbRBID));
- for (int i = 0; i < stencilFmtCnt && sbRBID; ++i) {
- const GrGLCaps::StencilFormat& sFmt = this->glCaps().stencilFormats()[i];
- CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
- GL_ALLOC_CALL(this->glInterface(), RenderbufferStorage(GR_GL_RENDERBUFFER,
- sFmt.fInternalFormat,
- kSize, kSize));
- if (GR_GL_NO_ERROR == CHECK_ALLOC_ERROR(this->glInterface())) {
- GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
- GR_GL_STENCIL_ATTACHMENT,
- GR_GL_RENDERBUFFER, sbRBID));
- if (sFmt.fPacked) {
- GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
- GR_GL_DEPTH_ATTACHMENT,
- GR_GL_RENDERBUFFER, sbRBID));
- } else {
- GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
- GR_GL_DEPTH_ATTACHMENT,
- GR_GL_RENDERBUFFER, 0));
- }
- GrGLenum status;
- GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
- if (status == GR_GL_FRAMEBUFFER_COMPLETE) {
- firstWorkingStencilFormatIndex = i;
- break;
- }
- GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
- GR_GL_STENCIL_ATTACHMENT,
- GR_GL_RENDERBUFFER, 0));
- if (sFmt.fPacked) {
- GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
- GR_GL_DEPTH_ATTACHMENT,
- GR_GL_RENDERBUFFER, 0));
- }
- }
- }
- GL_CALL(DeleteRenderbuffers(1, &sbRBID));
- }
- GL_CALL(DeleteTextures(1, &colorID));
- this->bindFramebuffer(GR_GL_FRAMEBUFFER, 0);
- this->deleteFramebuffer(fb);
- fGLContext->caps()->setStencilFormatIndexForFormat(format, firstWorkingStencilFormatIndex);
- }
- return this->glCaps().getStencilFormatIndexForFormat(format);
- }
- bool GrGLGpu::createTextureImpl(const GrSurfaceDesc& desc, GrGLTextureInfo* info,
- GrRenderable renderable,
- GrGLTextureParameters::SamplerOverriddenState* initialState,
- const GrMipLevel texels[], int mipLevelCount,
- GrMipMapsStatus* mipMapsStatus) {
- SkASSERT(!GrPixelConfigIsCompressed(desc.fConfig));
- info->fID = 0;
- info->fTarget = GR_GL_TEXTURE_2D;
- GL_CALL(GenTextures(1, &(info->fID)));
- if (!info->fID) {
- return false;
- }
- info->fFormat = this->glCaps().configSizedInternalFormat(desc.fConfig);
- this->bindTextureToScratchUnit(info->fTarget, info->fID);
- if (GrRenderable::kYes == renderable && this->glCaps().textureUsageSupport()) {
- // provides a hint about how this texture will be used
- GL_CALL(TexParameteri(info->fTarget,
- GR_GL_TEXTURE_USAGE,
- GR_GL_FRAMEBUFFER_ATTACHMENT));
- }
- *initialState = set_initial_texture_params(this->glInterface(), *info);
- if (!this->uploadTexData(desc.fConfig, desc.fWidth, desc.fHeight, info->fTarget,
- kNewTexture_UploadType, 0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
- texels, mipLevelCount, mipMapsStatus)) {
- GL_CALL(DeleteTextures(1, &(info->fID)));
- return false;
- }
- return true;
- }
- bool GrGLGpu::createCompressedTextureImpl(
- GrGLTextureInfo* info, int width, int height, SkImage::CompressionType compression,
- GrGLTextureParameters::SamplerOverriddenState* initialState, const void* data) {
- info->fID = 0;
- GL_CALL(GenTextures(1, &info->fID));
- if (!info->fID) {
- return false;
- }
- info->fTarget = GR_GL_TEXTURE_2D;
- this->bindTextureToScratchUnit(info->fTarget, info->fID);
- *initialState = set_initial_texture_params(this->glInterface(), *info);
- info->fFormat = this->uploadCompressedTexData(compression, width, height, info->fTarget, data);
- if (!info->fFormat) {
- GL_CALL(DeleteTextures(1, &info->fID));
- return false;
- }
- return true;
- }
- GrStencilAttachment* GrGLGpu::createStencilAttachmentForRenderTarget(
- const GrRenderTarget* rt, int width, int height, int numStencilSamples) {
- SkASSERT(width >= rt->width());
- SkASSERT(height >= rt->height());
- GrGLStencilAttachment::IDDesc sbDesc;
- auto rtFormat = GrGLBackendFormatToGLFormat(rt->backendFormat());
- int sIdx = this->getCompatibleStencilIndex(rtFormat);
- if (sIdx < 0) {
- return nullptr;
- }
- if (!sbDesc.fRenderbufferID) {
- GL_CALL(GenRenderbuffers(1, &sbDesc.fRenderbufferID));
- }
- if (!sbDesc.fRenderbufferID) {
- return nullptr;
- }
- GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, sbDesc.fRenderbufferID));
- const GrGLCaps::StencilFormat& sFmt = this->glCaps().stencilFormats()[sIdx];
- CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
- // we do this "if" so that we don't call the multisample
- // version on a GL that doesn't have an MSAA extension.
- if (numStencilSamples > 1) {
- SkAssertResult(renderbuffer_storage_msaa(*fGLContext,
- numStencilSamples,
- sFmt.fInternalFormat,
- width, height));
- } else {
- GL_ALLOC_CALL(this->glInterface(), RenderbufferStorage(GR_GL_RENDERBUFFER,
- sFmt.fInternalFormat,
- width, height));
- SkASSERT(GR_GL_NO_ERROR == CHECK_ALLOC_ERROR(this->glInterface()));
- }
- fStats.incStencilAttachmentCreates();
- // After sized formats we attempt an unsized format and take
- // whatever sizes GL gives us. In that case we query for the size.
- GrGLStencilAttachment::Format format = sFmt;
- get_stencil_rb_sizes(this->glInterface(), &format);
- GrGLStencilAttachment* stencil = new GrGLStencilAttachment(this,
- sbDesc,
- width,
- height,
- numStencilSamples,
- format);
- return stencil;
- }
- ////////////////////////////////////////////////////////////////////////////////
- sk_sp<GrGpuBuffer> GrGLGpu::onCreateBuffer(size_t size, GrGpuBufferType intendedType,
- GrAccessPattern accessPattern, const void* data) {
- return GrGLBuffer::Make(this, size, intendedType, accessPattern, data);
- }
- void GrGLGpu::flushScissor(const GrScissorState& scissorState, int rtWidth, int rtHeight,
- GrSurfaceOrigin rtOrigin) {
- if (scissorState.enabled()) {
- GrGLIRect scissor;
- scissor.setRelativeTo(rtHeight, scissorState.rect(), rtOrigin);
- // if the scissor fully contains the viewport then we fall through and
- // disable the scissor test.
- if (!scissor.contains(rtWidth, rtHeight)) {
- if (fHWScissorSettings.fRect != scissor) {
- scissor.pushToGLScissor(this->glInterface());
- fHWScissorSettings.fRect = scissor;
- }
- if (kYes_TriState != fHWScissorSettings.fEnabled) {
- GL_CALL(Enable(GR_GL_SCISSOR_TEST));
- fHWScissorSettings.fEnabled = kYes_TriState;
- }
- return;
- }
- }
- // See fall through note above
- this->disableScissor();
- }
- void GrGLGpu::flushWindowRectangles(const GrWindowRectsState& windowState,
- const GrGLRenderTarget* rt, GrSurfaceOrigin origin) {
- #ifndef USE_NSIGHT
- typedef GrWindowRectsState::Mode Mode;
- SkASSERT(!windowState.enabled() || rt->renderFBOID()); // Window rects can't be used on-screen.
- SkASSERT(windowState.numWindows() <= this->caps()->maxWindowRectangles());
- if (!this->caps()->maxWindowRectangles() ||
- fHWWindowRectsState.knownEqualTo(origin, rt->width(), rt->height(), windowState)) {
- return;
- }
- // This is purely a workaround for a spurious warning generated by gcc. Otherwise the above
- // assert would be sufficient. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=5912
- int numWindows = SkTMin(windowState.numWindows(), int(GrWindowRectangles::kMaxWindows));
- SkASSERT(windowState.numWindows() == numWindows);
- GrGLIRect glwindows[GrWindowRectangles::kMaxWindows];
- const SkIRect* skwindows = windowState.windows().data();
- for (int i = 0; i < numWindows; ++i) {
- glwindows[i].setRelativeTo(rt->height(), skwindows[i], origin);
- }
- GrGLenum glmode = (Mode::kExclusive == windowState.mode()) ? GR_GL_EXCLUSIVE : GR_GL_INCLUSIVE;
- GL_CALL(WindowRectangles(glmode, numWindows, glwindows->asInts()));
- fHWWindowRectsState.set(origin, rt->width(), rt->height(), windowState);
- #endif
- }
- void GrGLGpu::disableWindowRectangles() {
- #ifndef USE_NSIGHT
- if (!this->caps()->maxWindowRectangles() || fHWWindowRectsState.knownDisabled()) {
- return;
- }
- GL_CALL(WindowRectangles(GR_GL_EXCLUSIVE, 0, nullptr));
- fHWWindowRectsState.setDisabled();
- #endif
- }
- void GrGLGpu::resolveAndGenerateMipMapsForProcessorTextures(
- const GrPrimitiveProcessor& primProc,
- const GrPipeline& pipeline,
- const GrTextureProxy* const primProcTextures[],
- int numPrimitiveProcessorTextureSets) {
- auto genLevelsIfNeeded = [this](GrTexture* tex, const GrSamplerState& sampler) {
- SkASSERT(tex);
- if (sampler.filter() == GrSamplerState::Filter::kMipMap &&
- tex->texturePriv().mipMapped() == GrMipMapped::kYes &&
- tex->texturePriv().mipMapsAreDirty()) {
- SkASSERT(this->caps()->mipMapSupport());
- this->regenerateMipMapLevels(static_cast<GrGLTexture*>(tex));
- SkASSERT(!tex->asRenderTarget() || !tex->asRenderTarget()->needsResolve());
- } else if (auto* rt = tex->asRenderTarget()) {
- if (rt->needsResolve()) {
- this->resolveRenderTarget(rt);
- }
- }
- };
- for (int set = 0, tex = 0; set < numPrimitiveProcessorTextureSets; ++set) {
- for (int sampler = 0; sampler < primProc.numTextureSamplers(); ++sampler, ++tex) {
- GrTexture* texture = primProcTextures[tex]->peekTexture();
- genLevelsIfNeeded(texture, primProc.textureSampler(sampler).samplerState());
- }
- }
- GrFragmentProcessor::Iter iter(pipeline);
- while (const GrFragmentProcessor* fp = iter.next()) {
- for (int i = 0; i < fp->numTextureSamplers(); ++i) {
- const auto& textureSampler = fp->textureSampler(i);
- genLevelsIfNeeded(textureSampler.peekTexture(), textureSampler.samplerState());
- }
- }
- }
- bool GrGLGpu::flushGLState(GrRenderTarget* renderTarget,
- GrSurfaceOrigin origin,
- const GrPrimitiveProcessor& primProc,
- const GrPipeline& pipeline,
- const GrPipeline::FixedDynamicState* fixedDynamicState,
- const GrPipeline::DynamicStateArrays* dynamicStateArrays,
- int dynamicStateArraysLength,
- bool willDrawPoints) {
- const GrTextureProxy* const* primProcProxiesForMipRegen = nullptr;
- const GrTextureProxy* const* primProcProxiesToBind = nullptr;
- int numPrimProcTextureSets = 1; // number of texture per prim proc sampler.
- if (dynamicStateArrays && dynamicStateArrays->fPrimitiveProcessorTextures) {
- primProcProxiesForMipRegen = dynamicStateArrays->fPrimitiveProcessorTextures;
- numPrimProcTextureSets = dynamicStateArraysLength;
- } else if (fixedDynamicState && fixedDynamicState->fPrimitiveProcessorTextures) {
- primProcProxiesForMipRegen = fixedDynamicState->fPrimitiveProcessorTextures;
- primProcProxiesToBind = fixedDynamicState->fPrimitiveProcessorTextures;
- }
- SkASSERT(SkToBool(primProcProxiesForMipRegen) == SkToBool(primProc.numTextureSamplers()));
- sk_sp<GrGLProgram> program(fProgramCache->refProgram(this, renderTarget, origin, primProc,
- primProcProxiesForMipRegen,
- pipeline, willDrawPoints));
- if (!program) {
- GrCapsDebugf(this->caps(), "Failed to create program!\n");
- return false;
- }
- this->resolveAndGenerateMipMapsForProcessorTextures(
- primProc, pipeline, primProcProxiesForMipRegen, numPrimProcTextureSets);
- this->flushProgram(std::move(program));
- // Swizzle the blend to match what the shader will output.
- this->flushBlendAndColorWrite(
- pipeline.getXferProcessor().getBlendInfo(), pipeline.outputSwizzle());
- fHWProgram->updateUniformsAndTextureBindings(renderTarget, origin,
- primProc, pipeline, primProcProxiesToBind);
- GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(renderTarget);
- GrStencilSettings stencil;
- if (pipeline.isStencilEnabled()) {
- // TODO: attach stencil and create settings during render target flush.
- SkASSERT(glRT->renderTargetPriv().getStencilAttachment());
- stencil.reset(*pipeline.getUserStencil(), pipeline.hasStencilClip(),
- glRT->renderTargetPriv().numStencilBits());
- }
- this->flushStencil(stencil, origin);
- if (pipeline.isScissorEnabled()) {
- static constexpr SkIRect kBogusScissor{0, 0, 1, 1};
- GrScissorState state(fixedDynamicState ? fixedDynamicState->fScissorRect : kBogusScissor);
- this->flushScissor(state, glRT->width(), glRT->height(), origin);
- } else {
- this->disableScissor();
- }
- this->flushWindowRectangles(pipeline.getWindowRectsState(), glRT, origin);
- this->flushHWAAState(glRT, pipeline.isHWAntialiasState());
- // This must come after textures are flushed because a texture may need
- // to be msaa-resolved (which will modify bound FBO state).
- this->flushRenderTarget(glRT);
- return true;
- }
- void GrGLGpu::flushProgram(sk_sp<GrGLProgram> program) {
- if (!program) {
- fHWProgram.reset();
- fHWProgramID = 0;
- return;
- }
- SkASSERT((program == fHWProgram) == (fHWProgramID == program->programID()));
- if (program == fHWProgram) {
- return;
- }
- auto id = program->programID();
- SkASSERT(id);
- GL_CALL(UseProgram(id));
- fHWProgram = std::move(program);
- fHWProgramID = id;
- }
- void GrGLGpu::flushProgram(GrGLuint id) {
- SkASSERT(id);
- if (fHWProgramID == id) {
- SkASSERT(!fHWProgram);
- return;
- }
- fHWProgram.reset();
- GL_CALL(UseProgram(id));
- fHWProgramID = id;
- }
- void GrGLGpu::setupGeometry(const GrBuffer* indexBuffer,
- const GrBuffer* vertexBuffer,
- int baseVertex,
- const GrBuffer* instanceBuffer,
- int baseInstance,
- GrPrimitiveRestart enablePrimitiveRestart) {
- SkASSERT((enablePrimitiveRestart == GrPrimitiveRestart::kNo) || indexBuffer);
- GrGLAttribArrayState* attribState;
- if (indexBuffer) {
- SkASSERT(indexBuffer->isCpuBuffer() ||
- !static_cast<const GrGpuBuffer*>(indexBuffer)->isMapped());
- attribState = fHWVertexArrayState.bindInternalVertexArray(this, indexBuffer);
- } else {
- attribState = fHWVertexArrayState.bindInternalVertexArray(this);
- }
- int numAttribs = fHWProgram->numVertexAttributes() + fHWProgram->numInstanceAttributes();
- attribState->enableVertexArrays(this, numAttribs, enablePrimitiveRestart);
- if (int vertexStride = fHWProgram->vertexStride()) {
- SkASSERT(vertexBuffer);
- SkASSERT(vertexBuffer->isCpuBuffer() ||
- !static_cast<const GrGpuBuffer*>(vertexBuffer)->isMapped());
- size_t bufferOffset = baseVertex * static_cast<size_t>(vertexStride);
- for (int i = 0; i < fHWProgram->numVertexAttributes(); ++i) {
- const auto& attrib = fHWProgram->vertexAttribute(i);
- static constexpr int kDivisor = 0;
- attribState->set(this, attrib.fLocation, vertexBuffer, attrib.fCPUType, attrib.fGPUType,
- vertexStride, bufferOffset + attrib.fOffset, kDivisor);
- }
- }
- if (int instanceStride = fHWProgram->instanceStride()) {
- SkASSERT(instanceBuffer);
- SkASSERT(instanceBuffer->isCpuBuffer() ||
- !static_cast<const GrGpuBuffer*>(instanceBuffer)->isMapped());
- size_t bufferOffset = baseInstance * static_cast<size_t>(instanceStride);
- int attribIdx = fHWProgram->numVertexAttributes();
- for (int i = 0; i < fHWProgram->numInstanceAttributes(); ++i, ++attribIdx) {
- const auto& attrib = fHWProgram->instanceAttribute(i);
- static constexpr int kDivisor = 1;
- attribState->set(this, attrib.fLocation, instanceBuffer, attrib.fCPUType,
- attrib.fGPUType, instanceStride, bufferOffset + attrib.fOffset,
- kDivisor);
- }
- }
- }
- GrGLenum GrGLGpu::bindBuffer(GrGpuBufferType type, const GrBuffer* buffer) {
- this->handleDirtyContext();
- // Index buffer state is tied to the vertex array.
- if (GrGpuBufferType::kIndex == type) {
- this->bindVertexArray(0);
- }
- auto* bufferState = this->hwBufferState(type);
- if (buffer->isCpuBuffer()) {
- if (!bufferState->fBufferZeroKnownBound) {
- GL_CALL(BindBuffer(bufferState->fGLTarget, 0));
- bufferState->fBufferZeroKnownBound = true;
- bufferState->fBoundBufferUniqueID.makeInvalid();
- }
- } else if (static_cast<const GrGpuBuffer*>(buffer)->uniqueID() !=
- bufferState->fBoundBufferUniqueID) {
- const GrGLBuffer* glBuffer = static_cast<const GrGLBuffer*>(buffer);
- GL_CALL(BindBuffer(bufferState->fGLTarget, glBuffer->bufferID()));
- bufferState->fBufferZeroKnownBound = false;
- bufferState->fBoundBufferUniqueID = glBuffer->uniqueID();
- }
- return bufferState->fGLTarget;
- }
- void GrGLGpu::disableScissor() {
- if (kNo_TriState != fHWScissorSettings.fEnabled) {
- GL_CALL(Disable(GR_GL_SCISSOR_TEST));
- fHWScissorSettings.fEnabled = kNo_TriState;
- return;
- }
- }
- void GrGLGpu::clear(const GrFixedClip& clip, const SkPMColor4f& color,
- GrRenderTarget* target, GrSurfaceOrigin origin) {
- // parent class should never let us get here with no RT
- SkASSERT(target);
- SkASSERT(!this->caps()->performColorClearsAsDraws());
- SkASSERT(!clip.scissorEnabled() || !this->caps()->performPartialClearsAsDraws());
- this->handleDirtyContext();
- GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(target);
- if (clip.scissorEnabled()) {
- this->flushRenderTarget(glRT, origin, clip.scissorRect());
- } else {
- this->flushRenderTarget(glRT);
- }
- this->flushScissor(clip.scissorState(), glRT->width(), glRT->height(), origin);
- this->flushWindowRectangles(clip.windowRectsState(), glRT, origin);
- this->flushColorWrite(true);
- GrGLfloat r = color.fR, g = color.fG, b = color.fB, a = color.fA;
- if (this->glCaps().clearToBoundaryValuesIsBroken() &&
- (1 == r || 0 == r) && (1 == g || 0 == g) && (1 == b || 0 == b) && (1 == a || 0 == a)) {
- static const GrGLfloat safeAlpha1 = nextafter(1.f, 2.f);
- static const GrGLfloat safeAlpha0 = nextafter(0.f, -1.f);
- a = (1 == a) ? safeAlpha1 : safeAlpha0;
- }
- this->flushClearColor(r, g, b, a);
- GL_CALL(Clear(GR_GL_COLOR_BUFFER_BIT));
- }
- void GrGLGpu::clearStencil(GrRenderTarget* target, int clearValue) {
- SkASSERT(!this->caps()->performStencilClearsAsDraws());
- if (!target) {
- return;
- }
- GrStencilAttachment* sb = target->renderTargetPriv().getStencilAttachment();
- // this should only be called internally when we know we have a
- // stencil buffer.
- SkASSERT(sb);
- GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(target);
- this->flushRenderTargetNoColorWrites(glRT);
- this->disableScissor();
- this->disableWindowRectangles();
- GL_CALL(StencilMask(0xffffffff));
- GL_CALL(ClearStencil(clearValue));
- GL_CALL(Clear(GR_GL_STENCIL_BUFFER_BIT));
- fHWStencilSettings.invalidate();
- if (!clearValue) {
- sb->cleared();
- }
- }
- void GrGLGpu::clearStencilClip(const GrFixedClip& clip,
- bool insideStencilMask,
- GrRenderTarget* target, GrSurfaceOrigin origin) {
- SkASSERT(target);
- SkASSERT(!this->caps()->performStencilClearsAsDraws());
- this->handleDirtyContext();
- GrStencilAttachment* sb = target->renderTargetPriv().getStencilAttachment();
- // this should only be called internally when we know we have a
- // stencil buffer.
- SkASSERT(sb);
- GrGLint stencilBitCount = sb->bits();
- #if 0
- SkASSERT(stencilBitCount > 0);
- GrGLint clipStencilMask = (1 << (stencilBitCount - 1));
- #else
- // we could just clear the clip bit but when we go through
- // ANGLE a partial stencil mask will cause clears to be
- // turned into draws. Our contract on GrOpList says that
- // changing the clip between stencil passes may or may not
- // zero the client's clip bits. So we just clear the whole thing.
- static const GrGLint clipStencilMask = ~0;
- #endif
- GrGLint value;
- if (insideStencilMask) {
- value = (1 << (stencilBitCount - 1));
- } else {
- value = 0;
- }
- GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(target);
- this->flushRenderTargetNoColorWrites(glRT);
- this->flushScissor(clip.scissorState(), glRT->width(), glRT->height(), origin);
- this->flushWindowRectangles(clip.windowRectsState(), glRT, origin);
- GL_CALL(StencilMask((uint32_t) clipStencilMask));
- GL_CALL(ClearStencil(value));
- GL_CALL(Clear(GR_GL_STENCIL_BUFFER_BIT));
- fHWStencilSettings.invalidate();
- }
- bool GrGLGpu::readOrTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
- GrColorType dstColorType, void* offsetOrPtr,
- int rowWidthInPixels) {
- SkASSERT(surface);
- GrGLRenderTarget* renderTarget = static_cast<GrGLRenderTarget*>(surface->asRenderTarget());
- if (!renderTarget && !this->glCaps().canConfigBeFBOColorAttachment(surface->config())) {
- return false;
- }
- // TODO: Avoid this conversion by making GrGLCaps work with color types.
- auto dstAsConfig = GrColorTypeToPixelConfig(dstColorType);
- GrGLenum externalFormat;
- GrGLenum externalType;
- if (!this->glCaps().getReadPixelsFormat(surface->config(), dstAsConfig, &externalFormat,
- &externalType)) {
- return false;
- }
- if (renderTarget) {
- // resolve the render target if necessary
- switch (renderTarget->getResolveType()) {
- case GrGLRenderTarget::kCantResolve_ResolveType:
- return false;
- case GrGLRenderTarget::kAutoResolves_ResolveType:
- this->flushRenderTargetNoColorWrites(renderTarget);
- break;
- case GrGLRenderTarget::kCanResolve_ResolveType:
- this->onResolveRenderTarget(renderTarget);
- // we don't track the state of the READ FBO ID.
- this->bindFramebuffer(GR_GL_READ_FRAMEBUFFER, renderTarget->textureFBOID());
- break;
- default:
- SK_ABORT("Unknown resolve type");
- }
- } else {
- // Use a temporary FBO.
- this->bindSurfaceFBOForPixelOps(surface, GR_GL_FRAMEBUFFER, kSrc_TempFBOTarget);
- fHWBoundRenderTargetUniqueID.makeInvalid();
- }
- // the read rect is viewport-relative
- GrGLIRect readRect;
- readRect.setRelativeTo(surface->height(), left, top, width, height, kTopLeft_GrSurfaceOrigin);
- // determine if GL can read using the passed rowBytes or if we need a scratch buffer.
- if (rowWidthInPixels != width) {
- SkASSERT(this->glCaps().readPixelsRowBytesSupport());
- GL_CALL(PixelStorei(GR_GL_PACK_ROW_LENGTH, rowWidthInPixels));
- }
- GL_CALL(PixelStorei(GR_GL_PACK_ALIGNMENT, config_alignment(dstAsConfig)));
- bool reattachStencil = false;
- if (this->glCaps().detachStencilFromMSAABuffersBeforeReadPixels() &&
- renderTarget &&
- renderTarget->renderTargetPriv().getStencilAttachment() &&
- renderTarget->numSamples() > 1) {
- // Fix Adreno devices that won't read from MSAA framebuffers with stencil attached
- reattachStencil = true;
- GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_STENCIL_ATTACHMENT,
- GR_GL_RENDERBUFFER, 0));
- }
- GL_CALL(ReadPixels(readRect.fLeft, readRect.fBottom, readRect.fWidth, readRect.fHeight,
- externalFormat, externalType, offsetOrPtr));
- if (reattachStencil) {
- GrGLStencilAttachment* stencilAttachment = static_cast<GrGLStencilAttachment*>(
- renderTarget->renderTargetPriv().getStencilAttachment());
- GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_STENCIL_ATTACHMENT,
- GR_GL_RENDERBUFFER, stencilAttachment->renderbufferID()));
- }
- if (rowWidthInPixels != width) {
- SkASSERT(this->glCaps().readPixelsRowBytesSupport());
- GL_CALL(PixelStorei(GR_GL_PACK_ROW_LENGTH, 0));
- }
- if (!renderTarget) {
- this->unbindTextureFBOForPixelOps(GR_GL_FRAMEBUFFER, surface);
- }
- return true;
- }
- bool GrGLGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int height,
- GrColorType dstColorType, void* buffer, size_t rowBytes) {
- SkASSERT(surface);
- int bytesPerPixel = GrColorTypeBytesPerPixel(dstColorType);
- // GL_PACK_ROW_LENGTH is in terms of pixels not bytes.
- int rowPixelWidth;
- if (rowBytes == SkToSizeT(width * bytesPerPixel)) {
- rowPixelWidth = width;
- } else {
- SkASSERT(!(rowBytes % bytesPerPixel));
- rowPixelWidth = rowBytes / bytesPerPixel;
- }
- return this->readOrTransferPixelsFrom(surface, left, top, width, height, dstColorType, buffer,
- rowPixelWidth);
- }
- GrGpuRTCommandBuffer* GrGLGpu::getCommandBuffer(
- GrRenderTarget* rt, GrSurfaceOrigin origin, const SkRect& bounds,
- const GrGpuRTCommandBuffer::LoadAndStoreInfo& colorInfo,
- const GrGpuRTCommandBuffer::StencilLoadAndStoreInfo& stencilInfo) {
- if (!fCachedRTCommandBuffer) {
- fCachedRTCommandBuffer.reset(new GrGLGpuRTCommandBuffer(this));
- }
- fCachedRTCommandBuffer->set(rt, origin, colorInfo, stencilInfo);
- return fCachedRTCommandBuffer.get();
- }
- GrGpuTextureCommandBuffer* GrGLGpu::getCommandBuffer(GrTexture* texture, GrSurfaceOrigin origin) {
- if (!fCachedTexCommandBuffer) {
- fCachedTexCommandBuffer.reset(new GrGLGpuTextureCommandBuffer(this));
- }
- fCachedTexCommandBuffer->set(texture, origin);
- return fCachedTexCommandBuffer.get();
- }
- void GrGLGpu::flushRenderTarget(GrGLRenderTarget* target, GrSurfaceOrigin origin,
- const SkIRect& bounds) {
- this->flushRenderTargetNoColorWrites(target);
- this->didWriteToSurface(target, origin, &bounds);
- }
- void GrGLGpu::flushRenderTarget(GrGLRenderTarget* target) {
- this->flushRenderTargetNoColorWrites(target);
- this->didWriteToSurface(target, kTopLeft_GrSurfaceOrigin, nullptr);
- }
- void GrGLGpu::flushRenderTargetNoColorWrites(GrGLRenderTarget* target) {
- SkASSERT(target);
- GrGpuResource::UniqueID rtID = target->uniqueID();
- if (fHWBoundRenderTargetUniqueID != rtID) {
- this->bindFramebuffer(GR_GL_FRAMEBUFFER, target->renderFBOID());
- #ifdef SK_DEBUG
- // don't do this check in Chromium -- this is causing
- // lots of repeated command buffer flushes when the compositor is
- // rendering with Ganesh, which is really slow; even too slow for
- // Debug mode.
- if (kChromium_GrGLDriver != this->glContext().driver()) {
- GrGLenum status;
- GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
- if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
- SkDebugf("GrGLGpu::flushRenderTarget glCheckFramebufferStatus %x\n", status);
- }
- }
- #endif
- fHWBoundRenderTargetUniqueID = rtID;
- this->flushViewport(target->width(), target->height());
- }
- if (this->glCaps().srgbWriteControl()) {
- this->flushFramebufferSRGB(GrPixelConfigIsSRGB(target->config()));
- }
- }
- void GrGLGpu::flushFramebufferSRGB(bool enable) {
- if (enable && kYes_TriState != fHWSRGBFramebuffer) {
- GL_CALL(Enable(GR_GL_FRAMEBUFFER_SRGB));
- fHWSRGBFramebuffer = kYes_TriState;
- } else if (!enable && kNo_TriState != fHWSRGBFramebuffer) {
- GL_CALL(Disable(GR_GL_FRAMEBUFFER_SRGB));
- fHWSRGBFramebuffer = kNo_TriState;
- }
- }
- void GrGLGpu::flushViewport(int width, int height) {
- GrGLIRect viewport = {0, 0, width, height};
- if (fHWViewport != viewport) {
- viewport.pushToGLViewport(this->glInterface());
- fHWViewport = viewport;
- }
- }
- #define SWAP_PER_DRAW 0
- #if SWAP_PER_DRAW
- #if defined(SK_BUILD_FOR_MAC)
- #include <AGL/agl.h>
- #elif defined(SK_BUILD_FOR_WIN)
- #include <gl/GL.h>
- void SwapBuf() {
- DWORD procID = GetCurrentProcessId();
- HWND hwnd = GetTopWindow(GetDesktopWindow());
- while(hwnd) {
- DWORD wndProcID = 0;
- GetWindowThreadProcessId(hwnd, &wndProcID);
- if(wndProcID == procID) {
- SwapBuffers(GetDC(hwnd));
- }
- hwnd = GetNextWindow(hwnd, GW_HWNDNEXT);
- }
- }
- #endif
- #endif
- void GrGLGpu::draw(GrRenderTarget* renderTarget, GrSurfaceOrigin origin,
- const GrPrimitiveProcessor& primProc,
- const GrPipeline& pipeline,
- const GrPipeline::FixedDynamicState* fixedDynamicState,
- const GrPipeline::DynamicStateArrays* dynamicStateArrays,
- const GrMesh meshes[],
- int meshCount) {
- this->handleDirtyContext();
- bool hasPoints = false;
- for (int i = 0; i < meshCount; ++i) {
- if (meshes[i].primitiveType() == GrPrimitiveType::kPoints) {
- hasPoints = true;
- break;
- }
- }
- if (!this->flushGLState(renderTarget, origin, primProc, pipeline, fixedDynamicState,
- dynamicStateArrays, meshCount, hasPoints)) {
- return;
- }
- bool dynamicScissor = false;
- bool dynamicPrimProcTextures = false;
- if (dynamicStateArrays) {
- dynamicScissor = pipeline.isScissorEnabled() && dynamicStateArrays->fScissorRects;
- dynamicPrimProcTextures = dynamicStateArrays->fPrimitiveProcessorTextures;
- }
- for (int m = 0; m < meshCount; ++m) {
- if (GrXferBarrierType barrierType = pipeline.xferBarrierType(renderTarget->asTexture(),
- *this->caps())) {
- this->xferBarrier(renderTarget, barrierType);
- }
- if (dynamicScissor) {
- GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(renderTarget);
- this->flushScissor(GrScissorState(dynamicStateArrays->fScissorRects[m]),
- glRT->width(), glRT->height(), origin);
- }
- if (dynamicPrimProcTextures) {
- auto texProxyArray = dynamicStateArrays->fPrimitiveProcessorTextures +
- m * primProc.numTextureSamplers();
- fHWProgram->updatePrimitiveProcessorTextureBindings(primProc, texProxyArray);
- }
- if (this->glCaps().requiresCullFaceEnableDisableWhenDrawingLinesAfterNonLines() &&
- GrIsPrimTypeLines(meshes[m].primitiveType()) &&
- !GrIsPrimTypeLines(fLastPrimitiveType)) {
- GL_CALL(Enable(GR_GL_CULL_FACE));
- GL_CALL(Disable(GR_GL_CULL_FACE));
- }
- meshes[m].sendToGpu(this);
- fLastPrimitiveType = meshes[m].primitiveType();
- }
- #if SWAP_PER_DRAW
- glFlush();
- #if defined(SK_BUILD_FOR_MAC)
- aglSwapBuffers(aglGetCurrentContext());
- int set_a_break_pt_here = 9;
- aglSwapBuffers(aglGetCurrentContext());
- #elif defined(SK_BUILD_FOR_WIN)
- SwapBuf();
- int set_a_break_pt_here = 9;
- SwapBuf();
- #endif
- #endif
- }
- static GrGLenum gr_primitive_type_to_gl_mode(GrPrimitiveType primitiveType) {
- switch (primitiveType) {
- case GrPrimitiveType::kTriangles:
- return GR_GL_TRIANGLES;
- case GrPrimitiveType::kTriangleStrip:
- return GR_GL_TRIANGLE_STRIP;
- case GrPrimitiveType::kPoints:
- return GR_GL_POINTS;
- case GrPrimitiveType::kLines:
- return GR_GL_LINES;
- case GrPrimitiveType::kLineStrip:
- return GR_GL_LINE_STRIP;
- case GrPrimitiveType::kLinesAdjacency:
- return GR_GL_LINES_ADJACENCY;
- }
- SK_ABORT("invalid GrPrimitiveType");
- return GR_GL_TRIANGLES;
- }
- void GrGLGpu::sendMeshToGpu(GrPrimitiveType primitiveType, const GrBuffer* vertexBuffer,
- int vertexCount, int baseVertex) {
- const GrGLenum glPrimType = gr_primitive_type_to_gl_mode(primitiveType);
- if (this->glCaps().drawArraysBaseVertexIsBroken()) {
- this->setupGeometry(nullptr, vertexBuffer, baseVertex, nullptr, 0, GrPrimitiveRestart::kNo);
- GL_CALL(DrawArrays(glPrimType, 0, vertexCount));
- } else {
- this->setupGeometry(nullptr, vertexBuffer, 0, nullptr, 0, GrPrimitiveRestart::kNo);
- GL_CALL(DrawArrays(glPrimType, baseVertex, vertexCount));
- }
- fStats.incNumDraws();
- }
- static const GrGLvoid* element_ptr(const GrBuffer* indexBuffer, int baseIndex) {
- size_t baseOffset = baseIndex * sizeof(uint16_t);
- if (indexBuffer->isCpuBuffer()) {
- return static_cast<const GrCpuBuffer*>(indexBuffer)->data() + baseOffset;
- } else {
- return reinterpret_cast<const GrGLvoid*>(baseOffset);
- }
- }
- void GrGLGpu::sendIndexedMeshToGpu(GrPrimitiveType primitiveType, const GrBuffer* indexBuffer,
- int indexCount, int baseIndex, uint16_t minIndexValue,
- uint16_t maxIndexValue, const GrBuffer* vertexBuffer,
- int baseVertex, GrPrimitiveRestart enablePrimitiveRestart) {
- const GrGLenum glPrimType = gr_primitive_type_to_gl_mode(primitiveType);
- const GrGLvoid* elementPtr = element_ptr(indexBuffer, baseIndex);
- this->setupGeometry(indexBuffer, vertexBuffer, baseVertex, nullptr, 0, enablePrimitiveRestart);
- if (this->glCaps().drawRangeElementsSupport()) {
- GL_CALL(DrawRangeElements(glPrimType, minIndexValue, maxIndexValue, indexCount,
- GR_GL_UNSIGNED_SHORT, elementPtr));
- } else {
- GL_CALL(DrawElements(glPrimType, indexCount, GR_GL_UNSIGNED_SHORT, elementPtr));
- }
- fStats.incNumDraws();
- }
- void GrGLGpu::sendInstancedMeshToGpu(GrPrimitiveType primitiveType, const GrBuffer* vertexBuffer,
- int vertexCount, int baseVertex,
- const GrBuffer* instanceBuffer, int instanceCount,
- int baseInstance) {
- GrGLenum glPrimType = gr_primitive_type_to_gl_mode(primitiveType);
- int maxInstances = this->glCaps().maxInstancesPerDrawWithoutCrashing(instanceCount);
- for (int i = 0; i < instanceCount; i += maxInstances) {
- this->setupGeometry(nullptr, vertexBuffer, 0, instanceBuffer, baseInstance + i,
- GrPrimitiveRestart::kNo);
- GL_CALL(DrawArraysInstanced(glPrimType, baseVertex, vertexCount,
- SkTMin(instanceCount - i, maxInstances)));
- fStats.incNumDraws();
- }
- }
- void GrGLGpu::sendIndexedInstancedMeshToGpu(GrPrimitiveType primitiveType,
- const GrBuffer* indexBuffer, int indexCount,
- int baseIndex, const GrBuffer* vertexBuffer,
- int baseVertex, const GrBuffer* instanceBuffer,
- int instanceCount, int baseInstance,
- GrPrimitiveRestart enablePrimitiveRestart) {
- const GrGLenum glPrimType = gr_primitive_type_to_gl_mode(primitiveType);
- const GrGLvoid* elementPtr = element_ptr(indexBuffer, baseIndex);
- int maxInstances = this->glCaps().maxInstancesPerDrawWithoutCrashing(instanceCount);
- for (int i = 0; i < instanceCount; i += maxInstances) {
- this->setupGeometry(indexBuffer, vertexBuffer, baseVertex, instanceBuffer, baseInstance + i,
- enablePrimitiveRestart);
- GL_CALL(DrawElementsInstanced(glPrimType, indexCount, GR_GL_UNSIGNED_SHORT, elementPtr,
- SkTMin(instanceCount - i, maxInstances)));
- fStats.incNumDraws();
- }
- }
- void GrGLGpu::onResolveRenderTarget(GrRenderTarget* target) {
- GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(target);
- if (rt->needsResolve()) {
- // Some extensions automatically resolves the texture when it is read.
- if (this->glCaps().usesMSAARenderBuffers()) {
- SkASSERT(rt->textureFBOID() != rt->renderFBOID());
- SkASSERT(rt->textureFBOID() != 0 && rt->renderFBOID() != 0);
- this->bindFramebuffer(GR_GL_READ_FRAMEBUFFER, rt->renderFBOID());
- this->bindFramebuffer(GR_GL_DRAW_FRAMEBUFFER, rt->textureFBOID());
- // make sure we go through flushRenderTarget() since we've modified
- // the bound DRAW FBO ID.
- fHWBoundRenderTargetUniqueID.makeInvalid();
- const SkIRect dirtyRect = rt->getResolveRect();
- // The dirty rect tracked on the RT is always stored in the native coordinates of the
- // surface. Choose kTopLeft so no adjustments are made
- static constexpr auto kDirtyRectOrigin = kTopLeft_GrSurfaceOrigin;
- if (GrGLCaps::kES_Apple_MSFBOType == this->glCaps().msFBOType()) {
- // Apple's extension uses the scissor as the blit bounds.
- GrScissorState scissorState;
- scissorState.set(dirtyRect);
- this->flushScissor(scissorState, rt->width(), rt->height(), kDirtyRectOrigin);
- this->disableWindowRectangles();
- GL_CALL(ResolveMultisampleFramebuffer());
- } else {
- int l, b, r, t;
- if (GrGLCaps::kResolveMustBeFull_BlitFrambufferFlag &
- this->glCaps().blitFramebufferSupportFlags()) {
- l = 0;
- b = 0;
- r = target->width();
- t = target->height();
- } else {
- GrGLIRect rect;
- rect.setRelativeTo(rt->height(), dirtyRect, kDirtyRectOrigin);
- l = rect.fLeft;
- b = rect.fBottom;
- r = rect.fLeft + rect.fWidth;
- t = rect.fBottom + rect.fHeight;
- }
- // BlitFrameBuffer respects the scissor, so disable it.
- this->disableScissor();
- this->disableWindowRectangles();
- GL_CALL(BlitFramebuffer(l, b, r, t, l, b, r, t,
- GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST));
- }
- }
- rt->flagAsResolved();
- }
- }
- namespace {
- GrGLenum gr_to_gl_stencil_op(GrStencilOp op) {
- static const GrGLenum gTable[kGrStencilOpCount] = {
- GR_GL_KEEP, // kKeep
- GR_GL_ZERO, // kZero
- GR_GL_REPLACE, // kReplace
- GR_GL_INVERT, // kInvert
- GR_GL_INCR_WRAP, // kIncWrap
- GR_GL_DECR_WRAP, // kDecWrap
- GR_GL_INCR, // kIncClamp
- GR_GL_DECR, // kDecClamp
- };
- GR_STATIC_ASSERT(0 == (int)GrStencilOp::kKeep);
- GR_STATIC_ASSERT(1 == (int)GrStencilOp::kZero);
- GR_STATIC_ASSERT(2 == (int)GrStencilOp::kReplace);
- GR_STATIC_ASSERT(3 == (int)GrStencilOp::kInvert);
- GR_STATIC_ASSERT(4 == (int)GrStencilOp::kIncWrap);
- GR_STATIC_ASSERT(5 == (int)GrStencilOp::kDecWrap);
- GR_STATIC_ASSERT(6 == (int)GrStencilOp::kIncClamp);
- GR_STATIC_ASSERT(7 == (int)GrStencilOp::kDecClamp);
- SkASSERT(op < (GrStencilOp)kGrStencilOpCount);
- return gTable[(int)op];
- }
- void set_gl_stencil(const GrGLInterface* gl,
- const GrStencilSettings::Face& face,
- GrGLenum glFace) {
- GrGLenum glFunc = GrToGLStencilFunc(face.fTest);
- GrGLenum glFailOp = gr_to_gl_stencil_op(face.fFailOp);
- GrGLenum glPassOp = gr_to_gl_stencil_op(face.fPassOp);
- GrGLint ref = face.fRef;
- GrGLint mask = face.fTestMask;
- GrGLint writeMask = face.fWriteMask;
- if (GR_GL_FRONT_AND_BACK == glFace) {
- // we call the combined func just in case separate stencil is not
- // supported.
- GR_GL_CALL(gl, StencilFunc(glFunc, ref, mask));
- GR_GL_CALL(gl, StencilMask(writeMask));
- GR_GL_CALL(gl, StencilOp(glFailOp, GR_GL_KEEP, glPassOp));
- } else {
- GR_GL_CALL(gl, StencilFuncSeparate(glFace, glFunc, ref, mask));
- GR_GL_CALL(gl, StencilMaskSeparate(glFace, writeMask));
- GR_GL_CALL(gl, StencilOpSeparate(glFace, glFailOp, GR_GL_KEEP, glPassOp));
- }
- }
- }
- void GrGLGpu::flushStencil(const GrStencilSettings& stencilSettings, GrSurfaceOrigin origin) {
- if (stencilSettings.isDisabled()) {
- this->disableStencil();
- } else if (fHWStencilSettings != stencilSettings ||
- (stencilSettings.isTwoSided() && fHWStencilOrigin != origin)) {
- if (kYes_TriState != fHWStencilTestEnabled) {
- GL_CALL(Enable(GR_GL_STENCIL_TEST));
- fHWStencilTestEnabled = kYes_TriState;
- }
- if (stencilSettings.isTwoSided()) {
- set_gl_stencil(this->glInterface(), stencilSettings.front(origin), GR_GL_FRONT);
- set_gl_stencil(this->glInterface(), stencilSettings.back(origin), GR_GL_BACK);
- } else {
- set_gl_stencil(
- this->glInterface(), stencilSettings.frontAndBack(), GR_GL_FRONT_AND_BACK);
- }
- fHWStencilSettings = stencilSettings;
- fHWStencilOrigin = origin;
- }
- }
- void GrGLGpu::disableStencil() {
- if (kNo_TriState != fHWStencilTestEnabled) {
- GL_CALL(Disable(GR_GL_STENCIL_TEST));
- fHWStencilTestEnabled = kNo_TriState;
- fHWStencilSettings.invalidate();
- }
- }
- void GrGLGpu::flushHWAAState(GrRenderTarget* rt, bool useHWAA) {
- // rt is only optional if useHWAA is false.
- SkASSERT(rt || !useHWAA);
- #ifdef SK_DEBUG
- if (useHWAA && rt->numSamples() <= 1) {
- SkASSERT(this->caps()->mixedSamplesSupport());
- SkASSERT(0 != static_cast<GrGLRenderTarget*>(rt)->renderFBOID());
- SkASSERT(rt->renderTargetPriv().getStencilAttachment());
- }
- #endif
- if (this->caps()->multisampleDisableSupport()) {
- if (useHWAA) {
- if (kYes_TriState != fMSAAEnabled) {
- GL_CALL(Enable(GR_GL_MULTISAMPLE));
- fMSAAEnabled = kYes_TriState;
- }
- } else {
- if (kNo_TriState != fMSAAEnabled) {
- GL_CALL(Disable(GR_GL_MULTISAMPLE));
- fMSAAEnabled = kNo_TriState;
- }
- }
- }
- }
- void GrGLGpu::flushBlendAndColorWrite(
- const GrXferProcessor::BlendInfo& blendInfo, const GrSwizzle& swizzle) {
- if (this->glCaps().neverDisableColorWrites() && !blendInfo.fWriteColor) {
- // We need to work around a driver bug by using a blend state that preserves the dst color,
- // rather than disabling color writes.
- GrXferProcessor::BlendInfo preserveDstBlend;
- preserveDstBlend.fSrcBlend = kZero_GrBlendCoeff;
- preserveDstBlend.fDstBlend = kOne_GrBlendCoeff;
- this->flushBlendAndColorWrite(preserveDstBlend, swizzle);
- return;
- }
- GrBlendEquation equation = blendInfo.fEquation;
- GrBlendCoeff srcCoeff = blendInfo.fSrcBlend;
- GrBlendCoeff dstCoeff = blendInfo.fDstBlend;
- // Any optimization to disable blending should have already been applied and
- // tweaked the equation to "add" or "subtract", and the coeffs to (1, 0).
- bool blendOff =
- ((kAdd_GrBlendEquation == equation || kSubtract_GrBlendEquation == equation) &&
- kOne_GrBlendCoeff == srcCoeff && kZero_GrBlendCoeff == dstCoeff) ||
- !blendInfo.fWriteColor;
- if (blendOff) {
- if (kNo_TriState != fHWBlendState.fEnabled) {
- GL_CALL(Disable(GR_GL_BLEND));
- // Workaround for the ARM KHR_blend_equation_advanced blacklist issue
- // https://code.google.com/p/skia/issues/detail?id=3943
- if (kARM_GrGLVendor == this->ctxInfo().vendor() &&
- GrBlendEquationIsAdvanced(fHWBlendState.fEquation)) {
- SkASSERT(this->caps()->advancedBlendEquationSupport());
- // Set to any basic blending equation.
- GrBlendEquation blend_equation = kAdd_GrBlendEquation;
- GL_CALL(BlendEquation(gXfermodeEquation2Blend[blend_equation]));
- fHWBlendState.fEquation = blend_equation;
- }
- fHWBlendState.fEnabled = kNo_TriState;
- }
- } else {
- if (kYes_TriState != fHWBlendState.fEnabled) {
- GL_CALL(Enable(GR_GL_BLEND));
- fHWBlendState.fEnabled = kYes_TriState;
- }
- if (fHWBlendState.fEquation != equation) {
- GL_CALL(BlendEquation(gXfermodeEquation2Blend[equation]));
- fHWBlendState.fEquation = equation;
- }
- if (GrBlendEquationIsAdvanced(equation)) {
- SkASSERT(this->caps()->advancedBlendEquationSupport());
- // Advanced equations have no other blend state.
- return;
- }
- if (fHWBlendState.fSrcCoeff != srcCoeff || fHWBlendState.fDstCoeff != dstCoeff) {
- GL_CALL(BlendFunc(gXfermodeCoeff2Blend[srcCoeff],
- gXfermodeCoeff2Blend[dstCoeff]));
- fHWBlendState.fSrcCoeff = srcCoeff;
- fHWBlendState.fDstCoeff = dstCoeff;
- }
- if ((BlendCoeffReferencesConstant(srcCoeff) || BlendCoeffReferencesConstant(dstCoeff))) {
- SkPMColor4f blendConst = swizzle.applyTo(blendInfo.fBlendConstant);
- if (!fHWBlendState.fConstColorValid || fHWBlendState.fConstColor != blendConst) {
- GL_CALL(BlendColor(blendConst.fR, blendConst.fG, blendConst.fB, blendConst.fA));
- fHWBlendState.fConstColor = blendConst;
- fHWBlendState.fConstColorValid = true;
- }
- }
- }
- this->flushColorWrite(blendInfo.fWriteColor);
- }
- static void get_gl_swizzle_values(const GrSwizzle& swizzle, GrGLenum glValues[4]) {
- for (int i = 0; i < 4; ++i) {
- switch (swizzle[i]) {
- case 'r': glValues[i] = GR_GL_RED; break;
- case 'g': glValues[i] = GR_GL_GREEN; break;
- case 'b': glValues[i] = GR_GL_BLUE; break;
- case 'a': glValues[i] = GR_GL_ALPHA; break;
- case '0': glValues[i] = GR_GL_ZERO; break;
- case '1': glValues[i] = GR_GL_ONE; break;
- default: SK_ABORT("Unsupported component");
- }
- }
- }
- void GrGLGpu::bindTexture(int unitIdx, GrSamplerState samplerState, const GrSwizzle& swizzle,
- GrGLTexture* texture) {
- SkASSERT(texture);
- #ifdef SK_DEBUG
- if (!this->caps()->npotTextureTileSupport()) {
- if (samplerState.isRepeated()) {
- const int w = texture->width();
- const int h = texture->height();
- SkASSERT(SkIsPow2(w) && SkIsPow2(h));
- }
- }
- #endif
- // If we created a rt/tex and rendered to it without using a texture and now we're texturing
- // from the rt it will still be the last bound texture, but it needs resolving. So keep this
- // out of the "last != next" check.
- GrGLRenderTarget* texRT = static_cast<GrGLRenderTarget*>(texture->asRenderTarget());
- if (texRT) {
- this->onResolveRenderTarget(texRT);
- }
- GrGpuResource::UniqueID textureID = texture->uniqueID();
- GrGLenum target = texture->target();
- if (fHWTextureUnitBindings[unitIdx].boundID(target) != textureID) {
- this->setTextureUnit(unitIdx);
- GL_CALL(BindTexture(target, texture->textureID()));
- fHWTextureUnitBindings[unitIdx].setBoundID(target, textureID);
- }
- if (samplerState.filter() == GrSamplerState::Filter::kMipMap) {
- if (!this->caps()->mipMapSupport() ||
- texture->texturePriv().mipMapped() == GrMipMapped::kNo) {
- samplerState.setFilterMode(GrSamplerState::Filter::kBilerp);
- }
- }
- #ifdef SK_DEBUG
- // We were supposed to ensure MipMaps were up-to-date before getting here.
- if (samplerState.filter() == GrSamplerState::Filter::kMipMap) {
- SkASSERT(!texture->texturePriv().mipMapsAreDirty());
- }
- #endif
- auto timestamp = texture->parameters()->resetTimestamp();
- bool setAll = timestamp < fResetTimestampForTextureParameters;
- const GrGLTextureParameters::SamplerOverriddenState* samplerStateToRecord = nullptr;
- GrGLTextureParameters::SamplerOverriddenState newSamplerState;
- if (fSamplerObjectCache) {
- fSamplerObjectCache->bindSampler(unitIdx, samplerState);
- } else {
- const GrGLTextureParameters::SamplerOverriddenState& oldSamplerState =
- texture->parameters()->samplerOverriddenState();
- samplerStateToRecord = &newSamplerState;
- newSamplerState.fMinFilter = filter_to_gl_min_filter(samplerState.filter());
- newSamplerState.fMagFilter = filter_to_gl_mag_filter(samplerState.filter());
- newSamplerState.fWrapS = wrap_mode_to_gl_wrap(samplerState.wrapModeX(), this->glCaps());
- newSamplerState.fWrapT = wrap_mode_to_gl_wrap(samplerState.wrapModeY(), this->glCaps());
- // These are the OpenGL default values.
- newSamplerState.fMinLOD = -1000.f;
- newSamplerState.fMaxLOD = 1000.f;
- if (setAll || newSamplerState.fMagFilter != oldSamplerState.fMagFilter) {
- this->setTextureUnit(unitIdx);
- GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MAG_FILTER, newSamplerState.fMagFilter));
- }
- if (setAll || newSamplerState.fMinFilter != oldSamplerState.fMinFilter) {
- this->setTextureUnit(unitIdx);
- GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MIN_FILTER, newSamplerState.fMinFilter));
- }
- if (this->glCaps().mipMapLevelAndLodControlSupport()) {
- if (setAll || newSamplerState.fMinLOD != oldSamplerState.fMinLOD) {
- this->setTextureUnit(unitIdx);
- GL_CALL(TexParameterf(target, GR_GL_TEXTURE_MIN_LOD, newSamplerState.fMinLOD));
- }
- if (setAll || newSamplerState.fMaxLOD != oldSamplerState.fMaxLOD) {
- this->setTextureUnit(unitIdx);
- GL_CALL(TexParameterf(target, GR_GL_TEXTURE_MAX_LOD, newSamplerState.fMaxLOD));
- }
- }
- if (setAll || newSamplerState.fWrapS != oldSamplerState.fWrapS) {
- this->setTextureUnit(unitIdx);
- GL_CALL(TexParameteri(target, GR_GL_TEXTURE_WRAP_S, newSamplerState.fWrapS));
- }
- if (setAll || newSamplerState.fWrapT != oldSamplerState.fWrapT) {
- this->setTextureUnit(unitIdx);
- GL_CALL(TexParameteri(target, GR_GL_TEXTURE_WRAP_T, newSamplerState.fWrapT));
- }
- if (this->glCaps().clampToBorderSupport()) {
- // Make sure the border color is transparent black (the default)
- if (setAll || oldSamplerState.fBorderColorInvalid) {
- this->setTextureUnit(unitIdx);
- static const GrGLfloat kTransparentBlack[4] = {0.f, 0.f, 0.f, 0.f};
- GL_CALL(TexParameterfv(target, GR_GL_TEXTURE_BORDER_COLOR, kTransparentBlack));
- }
- }
- }
- GrGLTextureParameters::NonsamplerState newNonsamplerState;
- newNonsamplerState.fBaseMipMapLevel = 0;
- newNonsamplerState.fMaxMipMapLevel = texture->texturePriv().maxMipMapLevel();
- const GrGLTextureParameters::NonsamplerState& oldNonsamplerState =
- texture->parameters()->nonsamplerState();
- if (!this->caps()->shaderCaps()->textureSwizzleAppliedInShader()) {
- newNonsamplerState.fSwizzleKey = swizzle.asKey();
- if (setAll || swizzle.asKey() != oldNonsamplerState.fSwizzleKey) {
- GrGLenum glValues[4];
- get_gl_swizzle_values(swizzle, glValues);
- this->setTextureUnit(unitIdx);
- if (GR_IS_GR_GL(this->glStandard())) {
- GR_STATIC_ASSERT(sizeof(glValues[0]) == sizeof(GrGLint));
- GL_CALL(TexParameteriv(target, GR_GL_TEXTURE_SWIZZLE_RGBA,
- reinterpret_cast<const GrGLint*>(glValues)));
- } else if (GR_IS_GR_GL_ES(this->glStandard())) {
- // ES3 added swizzle support but not GL_TEXTURE_SWIZZLE_RGBA.
- GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_R, glValues[0]));
- GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_G, glValues[1]));
- GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_B, glValues[2]));
- GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_A, glValues[3]));
- }
- }
- }
- // These are not supported in ES2 contexts
- if (this->glCaps().mipMapLevelAndLodControlSupport() &&
- (texture->texturePriv().textureType() != GrTextureType::kExternal ||
- !this->glCaps().dontSetBaseOrMaxLevelForExternalTextures())) {
- if (newNonsamplerState.fBaseMipMapLevel != oldNonsamplerState.fBaseMipMapLevel) {
- this->setTextureUnit(unitIdx);
- GL_CALL(TexParameteri(target, GR_GL_TEXTURE_BASE_LEVEL,
- newNonsamplerState.fBaseMipMapLevel));
- }
- if (newNonsamplerState.fMaxMipMapLevel != oldNonsamplerState.fMaxMipMapLevel) {
- this->setTextureUnit(unitIdx);
- GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MAX_LEVEL,
- newNonsamplerState.fMaxMipMapLevel));
- }
- }
- texture->parameters()->set(samplerStateToRecord, newNonsamplerState,
- fResetTimestampForTextureParameters);
- }
- void GrGLGpu::onResetTextureBindings() {
- static constexpr GrGLenum kTargets[] = {GR_GL_TEXTURE_2D, GR_GL_TEXTURE_RECTANGLE,
- GR_GL_TEXTURE_EXTERNAL};
- for (int i = 0; i < this->numTextureUnits(); ++i) {
- this->setTextureUnit(i);
- for (auto target : kTargets) {
- if (fHWTextureUnitBindings[i].hasBeenModified(target)) {
- GL_CALL(BindTexture(target, 0));
- }
- }
- fHWTextureUnitBindings[i].invalidateAllTargets(true);
- }
- }
- void GrGLGpu::flushColorWrite(bool writeColor) {
- if (!writeColor) {
- if (kNo_TriState != fHWWriteToColor) {
- GL_CALL(ColorMask(GR_GL_FALSE, GR_GL_FALSE,
- GR_GL_FALSE, GR_GL_FALSE));
- fHWWriteToColor = kNo_TriState;
- }
- } else {
- if (kYes_TriState != fHWWriteToColor) {
- GL_CALL(ColorMask(GR_GL_TRUE, GR_GL_TRUE, GR_GL_TRUE, GR_GL_TRUE));
- fHWWriteToColor = kYes_TriState;
- }
- }
- }
- void GrGLGpu::flushClearColor(GrGLfloat r, GrGLfloat g, GrGLfloat b, GrGLfloat a) {
- if (r != fHWClearColor[0] || g != fHWClearColor[1] ||
- b != fHWClearColor[2] || a != fHWClearColor[3]) {
- GL_CALL(ClearColor(r, g, b, a));
- fHWClearColor[0] = r;
- fHWClearColor[1] = g;
- fHWClearColor[2] = b;
- fHWClearColor[3] = a;
- }
- }
- void GrGLGpu::setTextureUnit(int unit) {
- SkASSERT(unit >= 0 && unit < this->numTextureUnits());
- if (unit != fHWActiveTextureUnitIdx) {
- GL_CALL(ActiveTexture(GR_GL_TEXTURE0 + unit));
- fHWActiveTextureUnitIdx = unit;
- }
- }
- void GrGLGpu::bindTextureToScratchUnit(GrGLenum target, GrGLint textureID) {
- // Bind the last texture unit since it is the least likely to be used by GrGLProgram.
- int lastUnitIdx = this->numTextureUnits() - 1;
- if (lastUnitIdx != fHWActiveTextureUnitIdx) {
- GL_CALL(ActiveTexture(GR_GL_TEXTURE0 + lastUnitIdx));
- fHWActiveTextureUnitIdx = lastUnitIdx;
- }
- // Clear out the this field so that if a GrGLProgram does use this unit it will rebind the
- // correct texture.
- fHWTextureUnitBindings[lastUnitIdx].invalidateForScratchUse(target);
- GL_CALL(BindTexture(target, textureID));
- }
- // Determines whether glBlitFramebuffer could be used between src and dst by onCopySurface.
- static inline bool can_blit_framebuffer_for_copy_surface(const GrSurface* dst,
- const GrSurface* src,
- const SkIRect& srcRect,
- const SkIPoint& dstPoint,
- const GrGLCaps& caps) {
- int dstSampleCnt = 0;
- int srcSampleCnt = 0;
- if (const GrRenderTarget* rt = dst->asRenderTarget()) {
- dstSampleCnt = rt->numSamples();
- }
- if (const GrRenderTarget* rt = src->asRenderTarget()) {
- srcSampleCnt = rt->numSamples();
- }
- SkASSERT((dstSampleCnt > 0) == SkToBool(dst->asRenderTarget()));
- SkASSERT((srcSampleCnt > 0) == SkToBool(src->asRenderTarget()));
- const GrGLTexture* dstTex = static_cast<const GrGLTexture*>(dst->asTexture());
- const GrGLTexture* srcTex = static_cast<const GrGLTexture*>(src->asTexture());
- GrTextureType dstTexType;
- GrTextureType* dstTexTypePtr = nullptr;
- GrTextureType srcTexType;
- GrTextureType* srcTexTypePtr = nullptr;
- if (dstTex) {
- dstTexType = dstTex->texturePriv().textureType();
- dstTexTypePtr = &dstTexType;
- }
- if (srcTex) {
- srcTexType = srcTex->texturePriv().textureType();
- srcTexTypePtr = &srcTexType;
- }
- return caps.canCopyAsBlit(dst->config(), dstSampleCnt, dstTexTypePtr,
- src->config(), srcSampleCnt, srcTexTypePtr,
- src->getBoundsRect(), true, srcRect, dstPoint);
- }
- static bool rt_has_msaa_render_buffer(const GrGLRenderTarget* rt, const GrGLCaps& glCaps) {
- // A RT has a separate MSAA renderbuffer if:
- // 1) It's multisampled
- // 2) We're using an extension with separate MSAA renderbuffers
- // 3) It's not FBO 0, which is special and always auto-resolves
- return rt->numSamples() > 1 && glCaps.usesMSAARenderBuffers() && rt->renderFBOID() != 0;
- }
- static inline bool can_copy_texsubimage(const GrSurface* dst, const GrSurface* src,
- const GrGLCaps& caps) {
- const GrGLRenderTarget* dstRT = static_cast<const GrGLRenderTarget*>(dst->asRenderTarget());
- const GrGLRenderTarget* srcRT = static_cast<const GrGLRenderTarget*>(src->asRenderTarget());
- const GrGLTexture* dstTex = static_cast<const GrGLTexture*>(dst->asTexture());
- const GrGLTexture* srcTex = static_cast<const GrGLTexture*>(src->asTexture());
- bool dstHasMSAARenderBuffer = dstRT ? rt_has_msaa_render_buffer(dstRT, caps) : false;
- bool srcHasMSAARenderBuffer = srcRT ? rt_has_msaa_render_buffer(srcRT, caps) : false;
- GrTextureType dstTexType;
- GrTextureType* dstTexTypePtr = nullptr;
- GrTextureType srcTexType;
- GrTextureType* srcTexTypePtr = nullptr;
- if (dstTex) {
- dstTexType = dstTex->texturePriv().textureType();
- dstTexTypePtr = &dstTexType;
- }
- if (srcTex) {
- srcTexType = srcTex->texturePriv().textureType();
- srcTexTypePtr = &srcTexType;
- }
- return caps.canCopyTexSubImage(dst->config(), dstHasMSAARenderBuffer, dstTexTypePtr,
- src->config(), srcHasMSAARenderBuffer, srcTexTypePtr);
- }
- // If a temporary FBO was created, its non-zero ID is returned.
- void GrGLGpu::bindSurfaceFBOForPixelOps(GrSurface* surface, GrGLenum fboTarget,
- TempFBOTarget tempFBOTarget) {
- GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(surface->asRenderTarget());
- if (!rt) {
- SkASSERT(surface->asTexture());
- GrGLTexture* texture = static_cast<GrGLTexture*>(surface->asTexture());
- GrGLuint texID = texture->textureID();
- GrGLenum target = texture->target();
- GrGLuint* tempFBOID;
- tempFBOID = kSrc_TempFBOTarget == tempFBOTarget ? &fTempSrcFBOID : &fTempDstFBOID;
- if (0 == *tempFBOID) {
- GR_GL_CALL(this->glInterface(), GenFramebuffers(1, tempFBOID));
- }
- this->bindFramebuffer(fboTarget, *tempFBOID);
- GR_GL_CALL(this->glInterface(), FramebufferTexture2D(fboTarget,
- GR_GL_COLOR_ATTACHMENT0,
- target,
- texID,
- 0));
- texture->baseLevelWasBoundToFBO();
- } else {
- this->bindFramebuffer(fboTarget, rt->renderFBOID());
- }
- }
- void GrGLGpu::unbindTextureFBOForPixelOps(GrGLenum fboTarget, GrSurface* surface) {
- // bindSurfaceFBOForPixelOps temporarily binds textures that are not render targets to
- if (!surface->asRenderTarget()) {
- SkASSERT(surface->asTexture());
- GrGLenum textureTarget = static_cast<GrGLTexture*>(surface->asTexture())->target();
- GR_GL_CALL(this->glInterface(), FramebufferTexture2D(fboTarget,
- GR_GL_COLOR_ATTACHMENT0,
- textureTarget,
- 0,
- 0));
- }
- }
- void GrGLGpu::onFBOChanged() {
- if (this->caps()->workarounds().flush_on_framebuffer_change ||
- this->caps()->workarounds().restore_scissor_on_fbo_change) {
- GL_CALL(Flush());
- }
- }
- void GrGLGpu::bindFramebuffer(GrGLenum target, GrGLuint fboid) {
- fStats.incRenderTargetBinds();
- GL_CALL(BindFramebuffer(target, fboid));
- if (target == GR_GL_FRAMEBUFFER || target == GR_GL_DRAW_FRAMEBUFFER) {
- fBoundDrawFramebuffer = fboid;
- }
- if (this->caps()->workarounds().restore_scissor_on_fbo_change) {
- // The driver forgets the correct scissor when modifying the FBO binding.
- if (!fHWScissorSettings.fRect.isInvalid()) {
- fHWScissorSettings.fRect.pushToGLScissor(this->glInterface());
- }
- }
- this->onFBOChanged();
- }
- void GrGLGpu::deleteFramebuffer(GrGLuint fboid) {
- if (fboid == fBoundDrawFramebuffer &&
- this->caps()->workarounds().unbind_attachments_on_bound_render_fbo_delete) {
- // This workaround only applies to deleting currently bound framebuffers
- // on Adreno 420. Because this is a somewhat rare case, instead of
- // tracking all the attachments of every framebuffer instead just always
- // unbind all attachments.
- GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0,
- GR_GL_RENDERBUFFER, 0));
- GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_STENCIL_ATTACHMENT,
- GR_GL_RENDERBUFFER, 0));
- GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_DEPTH_ATTACHMENT,
- GR_GL_RENDERBUFFER, 0));
- }
- GL_CALL(DeleteFramebuffers(1, &fboid));
- // Deleting the currently bound framebuffer rebinds to 0.
- if (fboid == fBoundDrawFramebuffer) {
- this->onFBOChanged();
- }
- }
- bool GrGLGpu::onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
- const SkIPoint& dstPoint, bool canDiscardOutsideDstRect) {
- // Don't prefer copying as a draw if the dst doesn't already have a FBO object.
- // This implicitly handles this->glCaps().useDrawInsteadOfAllRenderTargetWrites().
- bool preferCopy = SkToBool(dst->asRenderTarget());
- if (preferCopy && this->glCaps().canCopyAsDraw(dst->config(), SkToBool(src->asTexture()))) {
- if (this->copySurfaceAsDraw(dst, src, srcRect, dstPoint)) {
- return true;
- }
- }
- if (can_copy_texsubimage(dst, src, this->glCaps())) {
- this->copySurfaceAsCopyTexSubImage(dst, src, srcRect, dstPoint);
- return true;
- }
- if (can_blit_framebuffer_for_copy_surface(dst, src, srcRect, dstPoint, this->glCaps())) {
- return this->copySurfaceAsBlitFramebuffer(dst, src, srcRect, dstPoint);
- }
- if (!preferCopy && this->glCaps().canCopyAsDraw(dst->config(), SkToBool(src->asTexture()))) {
- if (this->copySurfaceAsDraw(dst, src, srcRect, dstPoint)) {
- return true;
- }
- }
- return false;
- }
- bool GrGLGpu::createCopyProgram(GrTexture* srcTex) {
- TRACE_EVENT0("skia.gpu", TRACE_FUNC);
- int progIdx = TextureToCopyProgramIdx(srcTex);
- const GrShaderCaps* shaderCaps = this->caps()->shaderCaps();
- GrSLType samplerType =
- GrSLCombinedSamplerTypeForTextureType(srcTex->texturePriv().textureType());
- if (!fCopyProgramArrayBuffer) {
- static const GrGLfloat vdata[] = {
- 0, 0,
- 0, 1,
- 1, 0,
- 1, 1
- };
- fCopyProgramArrayBuffer = GrGLBuffer::Make(this, sizeof(vdata), GrGpuBufferType::kVertex,
- kStatic_GrAccessPattern, vdata);
- }
- if (!fCopyProgramArrayBuffer) {
- return false;
- }
- SkASSERT(!fCopyPrograms[progIdx].fProgram);
- GL_CALL_RET(fCopyPrograms[progIdx].fProgram, CreateProgram());
- if (!fCopyPrograms[progIdx].fProgram) {
- return false;
- }
- GrShaderVar aVertex("a_vertex", kHalf2_GrSLType, GrShaderVar::kIn_TypeModifier);
- GrShaderVar uTexCoordXform("u_texCoordXform", kHalf4_GrSLType,
- GrShaderVar::kUniform_TypeModifier);
- GrShaderVar uPosXform("u_posXform", kHalf4_GrSLType, GrShaderVar::kUniform_TypeModifier);
- GrShaderVar uTexture("u_texture", samplerType, GrShaderVar::kUniform_TypeModifier);
- GrShaderVar vTexCoord("v_texCoord", kHalf2_GrSLType, GrShaderVar::kOut_TypeModifier);
- GrShaderVar oFragColor("o_FragColor", kHalf4_GrSLType, GrShaderVar::kOut_TypeModifier);
- SkString vshaderTxt;
- if (shaderCaps->noperspectiveInterpolationSupport()) {
- if (const char* extension = shaderCaps->noperspectiveInterpolationExtensionString()) {
- vshaderTxt.appendf("#extension %s : require\n", extension);
- }
- vTexCoord.addModifier("noperspective");
- }
- aVertex.appendDecl(shaderCaps, &vshaderTxt);
- vshaderTxt.append(";");
- uTexCoordXform.appendDecl(shaderCaps, &vshaderTxt);
- vshaderTxt.append(";");
- uPosXform.appendDecl(shaderCaps, &vshaderTxt);
- vshaderTxt.append(";");
- vTexCoord.appendDecl(shaderCaps, &vshaderTxt);
- vshaderTxt.append(";");
- vshaderTxt.append(
- "// Copy Program VS\n"
- "void main() {"
- " v_texCoord = half2(a_vertex.xy * u_texCoordXform.xy + u_texCoordXform.zw);"
- " sk_Position.xy = a_vertex * u_posXform.xy + u_posXform.zw;"
- " sk_Position.zw = half2(0, 1);"
- "}"
- );
- SkString fshaderTxt;
- if (shaderCaps->noperspectiveInterpolationSupport()) {
- if (const char* extension = shaderCaps->noperspectiveInterpolationExtensionString()) {
- fshaderTxt.appendf("#extension %s : require\n", extension);
- }
- }
- vTexCoord.setTypeModifier(GrShaderVar::kIn_TypeModifier);
- vTexCoord.appendDecl(shaderCaps, &fshaderTxt);
- fshaderTxt.append(";");
- uTexture.appendDecl(shaderCaps, &fshaderTxt);
- fshaderTxt.append(";");
- fshaderTxt.appendf(
- "// Copy Program FS\n"
- "void main() {"
- " sk_FragColor = texture(u_texture, v_texCoord);"
- "}"
- );
- auto errorHandler = this->getContext()->priv().getShaderErrorHandler();
- SkSL::String sksl(vshaderTxt.c_str(), vshaderTxt.size());
- SkSL::Program::Settings settings;
- settings.fCaps = shaderCaps;
- SkSL::String glsl;
- std::unique_ptr<SkSL::Program> program = GrSkSLtoGLSL(*fGLContext, SkSL::Program::kVertex_Kind,
- sksl, settings, &glsl, errorHandler);
- GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fCopyPrograms[progIdx].fProgram,
- GR_GL_VERTEX_SHADER, glsl, &fStats, errorHandler);
- SkASSERT(program->fInputs.isEmpty());
- sksl.assign(fshaderTxt.c_str(), fshaderTxt.size());
- program = GrSkSLtoGLSL(*fGLContext, SkSL::Program::kFragment_Kind, sksl, settings, &glsl,
- errorHandler);
- GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fCopyPrograms[progIdx].fProgram,
- GR_GL_FRAGMENT_SHADER, glsl, &fStats,
- errorHandler);
- SkASSERT(program->fInputs.isEmpty());
- GL_CALL(LinkProgram(fCopyPrograms[progIdx].fProgram));
- GL_CALL_RET(fCopyPrograms[progIdx].fTextureUniform,
- GetUniformLocation(fCopyPrograms[progIdx].fProgram, "u_texture"));
- GL_CALL_RET(fCopyPrograms[progIdx].fPosXformUniform,
- GetUniformLocation(fCopyPrograms[progIdx].fProgram, "u_posXform"));
- GL_CALL_RET(fCopyPrograms[progIdx].fTexCoordXformUniform,
- GetUniformLocation(fCopyPrograms[progIdx].fProgram, "u_texCoordXform"));
- GL_CALL(BindAttribLocation(fCopyPrograms[progIdx].fProgram, 0, "a_vertex"));
- GL_CALL(DeleteShader(vshader));
- GL_CALL(DeleteShader(fshader));
- return true;
- }
- bool GrGLGpu::createMipmapProgram(int progIdx) {
- const bool oddWidth = SkToBool(progIdx & 0x2);
- const bool oddHeight = SkToBool(progIdx & 0x1);
- const int numTaps = (oddWidth ? 2 : 1) * (oddHeight ? 2 : 1);
- const GrShaderCaps* shaderCaps = this->caps()->shaderCaps();
- SkASSERT(!fMipmapPrograms[progIdx].fProgram);
- GL_CALL_RET(fMipmapPrograms[progIdx].fProgram, CreateProgram());
- if (!fMipmapPrograms[progIdx].fProgram) {
- return false;
- }
- GrShaderVar aVertex("a_vertex", kHalf2_GrSLType, GrShaderVar::kIn_TypeModifier);
- GrShaderVar uTexCoordXform("u_texCoordXform", kHalf4_GrSLType,
- GrShaderVar::kUniform_TypeModifier);
- GrShaderVar uTexture("u_texture", kTexture2DSampler_GrSLType,
- GrShaderVar::kUniform_TypeModifier);
- // We need 1, 2, or 4 texture coordinates (depending on parity of each dimension):
- GrShaderVar vTexCoords[] = {
- GrShaderVar("v_texCoord0", kHalf2_GrSLType, GrShaderVar::kOut_TypeModifier),
- GrShaderVar("v_texCoord1", kHalf2_GrSLType, GrShaderVar::kOut_TypeModifier),
- GrShaderVar("v_texCoord2", kHalf2_GrSLType, GrShaderVar::kOut_TypeModifier),
- GrShaderVar("v_texCoord3", kHalf2_GrSLType, GrShaderVar::kOut_TypeModifier),
- };
- GrShaderVar oFragColor("o_FragColor", kHalf4_GrSLType,GrShaderVar::kOut_TypeModifier);
- SkString vshaderTxt;
- if (shaderCaps->noperspectiveInterpolationSupport()) {
- if (const char* extension = shaderCaps->noperspectiveInterpolationExtensionString()) {
- vshaderTxt.appendf("#extension %s : require\n", extension);
- }
- vTexCoords[0].addModifier("noperspective");
- vTexCoords[1].addModifier("noperspective");
- vTexCoords[2].addModifier("noperspective");
- vTexCoords[3].addModifier("noperspective");
- }
- aVertex.appendDecl(shaderCaps, &vshaderTxt);
- vshaderTxt.append(";");
- uTexCoordXform.appendDecl(shaderCaps, &vshaderTxt);
- vshaderTxt.append(";");
- for (int i = 0; i < numTaps; ++i) {
- vTexCoords[i].appendDecl(shaderCaps, &vshaderTxt);
- vshaderTxt.append(";");
- }
- vshaderTxt.append(
- "// Mipmap Program VS\n"
- "void main() {"
- " sk_Position.xy = a_vertex * half2(2, 2) - half2(1, 1);"
- " sk_Position.zw = half2(0, 1);"
- );
- // Insert texture coordinate computation:
- if (oddWidth && oddHeight) {
- vshaderTxt.append(
- " v_texCoord0 = a_vertex.xy * u_texCoordXform.yw;"
- " v_texCoord1 = a_vertex.xy * u_texCoordXform.yw + half2(u_texCoordXform.x, 0);"
- " v_texCoord2 = a_vertex.xy * u_texCoordXform.yw + half2(0, u_texCoordXform.z);"
- " v_texCoord3 = a_vertex.xy * u_texCoordXform.yw + u_texCoordXform.xz;"
- );
- } else if (oddWidth) {
- vshaderTxt.append(
- " v_texCoord0 = a_vertex.xy * half2(u_texCoordXform.y, 1);"
- " v_texCoord1 = a_vertex.xy * half2(u_texCoordXform.y, 1) + half2(u_texCoordXform.x, 0);"
- );
- } else if (oddHeight) {
- vshaderTxt.append(
- " v_texCoord0 = a_vertex.xy * half2(1, u_texCoordXform.w);"
- " v_texCoord1 = a_vertex.xy * half2(1, u_texCoordXform.w) + half2(0, u_texCoordXform.z);"
- );
- } else {
- vshaderTxt.append(
- " v_texCoord0 = a_vertex.xy;"
- );
- }
- vshaderTxt.append("}");
- SkString fshaderTxt;
- if (shaderCaps->noperspectiveInterpolationSupport()) {
- if (const char* extension = shaderCaps->noperspectiveInterpolationExtensionString()) {
- fshaderTxt.appendf("#extension %s : require\n", extension);
- }
- }
- for (int i = 0; i < numTaps; ++i) {
- vTexCoords[i].setTypeModifier(GrShaderVar::kIn_TypeModifier);
- vTexCoords[i].appendDecl(shaderCaps, &fshaderTxt);
- fshaderTxt.append(";");
- }
- uTexture.appendDecl(shaderCaps, &fshaderTxt);
- fshaderTxt.append(";");
- fshaderTxt.append(
- "// Mipmap Program FS\n"
- "void main() {"
- );
- if (oddWidth && oddHeight) {
- fshaderTxt.append(
- " sk_FragColor = (texture(u_texture, v_texCoord0) + "
- " texture(u_texture, v_texCoord1) + "
- " texture(u_texture, v_texCoord2) + "
- " texture(u_texture, v_texCoord3)) * 0.25;"
- );
- } else if (oddWidth || oddHeight) {
- fshaderTxt.append(
- " sk_FragColor = (texture(u_texture, v_texCoord0) + "
- " texture(u_texture, v_texCoord1)) * 0.5;"
- );
- } else {
- fshaderTxt.append(
- " sk_FragColor = texture(u_texture, v_texCoord0);"
- );
- }
- fshaderTxt.append("}");
- auto errorHandler = this->getContext()->priv().getShaderErrorHandler();
- SkSL::String sksl(vshaderTxt.c_str(), vshaderTxt.size());
- SkSL::Program::Settings settings;
- settings.fCaps = shaderCaps;
- SkSL::String glsl;
- std::unique_ptr<SkSL::Program> program = GrSkSLtoGLSL(*fGLContext, SkSL::Program::kVertex_Kind,
- sksl, settings, &glsl, errorHandler);
- GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fMipmapPrograms[progIdx].fProgram,
- GR_GL_VERTEX_SHADER, glsl, &fStats, errorHandler);
- SkASSERT(program->fInputs.isEmpty());
- sksl.assign(fshaderTxt.c_str(), fshaderTxt.size());
- program = GrSkSLtoGLSL(*fGLContext, SkSL::Program::kFragment_Kind, sksl, settings, &glsl,
- errorHandler);
- GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fMipmapPrograms[progIdx].fProgram,
- GR_GL_FRAGMENT_SHADER, glsl, &fStats,
- errorHandler);
- SkASSERT(program->fInputs.isEmpty());
- GL_CALL(LinkProgram(fMipmapPrograms[progIdx].fProgram));
- GL_CALL_RET(fMipmapPrograms[progIdx].fTextureUniform,
- GetUniformLocation(fMipmapPrograms[progIdx].fProgram, "u_texture"));
- GL_CALL_RET(fMipmapPrograms[progIdx].fTexCoordXformUniform,
- GetUniformLocation(fMipmapPrograms[progIdx].fProgram, "u_texCoordXform"));
- GL_CALL(BindAttribLocation(fMipmapPrograms[progIdx].fProgram, 0, "a_vertex"));
- GL_CALL(DeleteShader(vshader));
- GL_CALL(DeleteShader(fshader));
- return true;
- }
- bool GrGLGpu::copySurfaceAsDraw(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
- const SkIPoint& dstPoint) {
- GrGLTexture* srcTex = static_cast<GrGLTexture*>(src->asTexture());
- int progIdx = TextureToCopyProgramIdx(srcTex);
- if (!this->glCaps().canConfigBeFBOColorAttachment(dst->config())) {
- return false;
- }
- if (!fCopyPrograms[progIdx].fProgram) {
- if (!this->createCopyProgram(srcTex)) {
- SkDebugf("Failed to create copy program.\n");
- return false;
- }
- }
- int w = srcRect.width();
- int h = srcRect.height();
- // We don't swizzle at all in our copies.
- this->bindTexture(0, GrSamplerState::ClampNearest(), GrSwizzle::RGBA(), srcTex);
- this->bindSurfaceFBOForPixelOps(dst, GR_GL_FRAMEBUFFER, kDst_TempFBOTarget);
- this->flushViewport(dst->width(), dst->height());
- fHWBoundRenderTargetUniqueID.makeInvalid();
- SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, w, h);
- this->flushProgram(fCopyPrograms[progIdx].fProgram);
- fHWVertexArrayState.setVertexArrayID(this, 0);
- GrGLAttribArrayState* attribs = fHWVertexArrayState.bindInternalVertexArray(this);
- attribs->enableVertexArrays(this, 1);
- attribs->set(this, 0, fCopyProgramArrayBuffer.get(), kFloat2_GrVertexAttribType,
- kFloat2_GrSLType, 2 * sizeof(GrGLfloat), 0);
- // dst rect edges in NDC (-1 to 1)
- int dw = dst->width();
- int dh = dst->height();
- GrGLfloat dx0 = 2.f * dstPoint.fX / dw - 1.f;
- GrGLfloat dx1 = 2.f * (dstPoint.fX + w) / dw - 1.f;
- GrGLfloat dy0 = 2.f * dstPoint.fY / dh - 1.f;
- GrGLfloat dy1 = 2.f * (dstPoint.fY + h) / dh - 1.f;
- GrGLfloat sx0 = (GrGLfloat)srcRect.fLeft;
- GrGLfloat sx1 = (GrGLfloat)(srcRect.fLeft + w);
- GrGLfloat sy0 = (GrGLfloat)srcRect.fTop;
- GrGLfloat sy1 = (GrGLfloat)(srcRect.fTop + h);
- int sw = src->width();
- int sh = src->height();
- if (srcTex->texturePriv().textureType() != GrTextureType::kRectangle) {
- // src rect edges in normalized texture space (0 to 1)
- sx0 /= sw;
- sx1 /= sw;
- sy0 /= sh;
- sy1 /= sh;
- }
- GL_CALL(Uniform4f(fCopyPrograms[progIdx].fPosXformUniform, dx1 - dx0, dy1 - dy0, dx0, dy0));
- GL_CALL(Uniform4f(fCopyPrograms[progIdx].fTexCoordXformUniform,
- sx1 - sx0, sy1 - sy0, sx0, sy0));
- GL_CALL(Uniform1i(fCopyPrograms[progIdx].fTextureUniform, 0));
- this->flushBlendAndColorWrite(GrXferProcessor::BlendInfo(), GrSwizzle::RGBA());
- this->flushHWAAState(nullptr, false);
- this->disableScissor();
- this->disableWindowRectangles();
- this->disableStencil();
- if (this->glCaps().srgbWriteControl()) {
- this->flushFramebufferSRGB(true);
- }
- GL_CALL(DrawArrays(GR_GL_TRIANGLE_STRIP, 0, 4));
- this->unbindTextureFBOForPixelOps(GR_GL_FRAMEBUFFER, dst);
- // The rect is already in device space so we pass in kTopLeft so no flip is done.
- this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect);
- return true;
- }
- void GrGLGpu::copySurfaceAsCopyTexSubImage(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
- const SkIPoint& dstPoint) {
- SkASSERT(can_copy_texsubimage(dst, src, this->glCaps()));
- this->bindSurfaceFBOForPixelOps(src, GR_GL_FRAMEBUFFER, kSrc_TempFBOTarget);
- GrGLTexture* dstTex = static_cast<GrGLTexture *>(dst->asTexture());
- SkASSERT(dstTex);
- // We modified the bound FBO
- fHWBoundRenderTargetUniqueID.makeInvalid();
- this->bindTextureToScratchUnit(dstTex->target(), dstTex->textureID());
- GL_CALL(CopyTexSubImage2D(dstTex->target(), 0,
- dstPoint.fX, dstPoint.fY,
- srcRect.fLeft, srcRect.fTop,
- srcRect.width(), srcRect.height()));
- this->unbindTextureFBOForPixelOps(GR_GL_FRAMEBUFFER, src);
- SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
- srcRect.width(), srcRect.height());
- // The rect is already in device space so we pass in kTopLeft so no flip is done.
- this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect);
- }
- bool GrGLGpu::copySurfaceAsBlitFramebuffer(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
- const SkIPoint& dstPoint) {
- SkASSERT(can_blit_framebuffer_for_copy_surface(dst, src, srcRect, dstPoint, this->glCaps()));
- SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
- srcRect.width(), srcRect.height());
- if (dst == src) {
- if (SkIRect::IntersectsNoEmptyCheck(dstRect, srcRect)) {
- return false;
- }
- }
- this->bindSurfaceFBOForPixelOps(dst, GR_GL_DRAW_FRAMEBUFFER, kDst_TempFBOTarget);
- this->bindSurfaceFBOForPixelOps(src, GR_GL_READ_FRAMEBUFFER, kSrc_TempFBOTarget);
- // We modified the bound FBO
- fHWBoundRenderTargetUniqueID.makeInvalid();
- // BlitFrameBuffer respects the scissor, so disable it.
- this->disableScissor();
- this->disableWindowRectangles();
- GL_CALL(BlitFramebuffer(srcRect.fLeft,
- srcRect.fTop,
- srcRect.fRight,
- srcRect.fBottom,
- dstRect.fLeft,
- dstRect.fTop,
- dstRect.fRight,
- dstRect.fBottom,
- GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST));
- this->unbindTextureFBOForPixelOps(GR_GL_DRAW_FRAMEBUFFER, dst);
- this->unbindTextureFBOForPixelOps(GR_GL_READ_FRAMEBUFFER, src);
- // The rect is already in device space so we pass in kTopLeft so no flip is done.
- this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect);
- return true;
- }
- bool GrGLGpu::onRegenerateMipMapLevels(GrTexture* texture) {
- auto glTex = static_cast<GrGLTexture*>(texture);
- // Mipmaps are only supported on 2D textures:
- if (GR_GL_TEXTURE_2D != glTex->target()) {
- return false;
- }
- // Manual implementation of mipmap generation, to work around driver bugs w/sRGB.
- // Uses draw calls to do a series of downsample operations to successive mips.
- // The manual approach requires the ability to limit which level we're sampling and that the
- // destination can be bound to a FBO:
- if (!this->glCaps().doManualMipmapping() ||
- !this->glCaps().canConfigBeFBOColorAttachment(texture->config())) {
- GrGLenum target = glTex->target();
- this->bindTextureToScratchUnit(target, glTex->textureID());
- GL_CALL(GenerateMipmap(glTex->target()));
- return true;
- }
- int width = texture->width();
- int height = texture->height();
- int levelCount = SkMipMap::ComputeLevelCount(width, height) + 1;
- SkASSERT(levelCount == texture->texturePriv().maxMipMapLevel() + 1);
- // Create (if necessary), then bind temporary FBO:
- if (0 == fTempDstFBOID) {
- GL_CALL(GenFramebuffers(1, &fTempDstFBOID));
- }
- this->bindFramebuffer(GR_GL_FRAMEBUFFER, fTempDstFBOID);
- fHWBoundRenderTargetUniqueID.makeInvalid();
- // Bind the texture, to get things configured for filtering.
- // We'll be changing our base level further below:
- this->setTextureUnit(0);
- // The mipmap program does not do any swizzling.
- this->bindTexture(0, GrSamplerState::ClampBilerp(), GrSwizzle::RGBA(), glTex);
- // Vertex data:
- if (!fMipmapProgramArrayBuffer) {
- static const GrGLfloat vdata[] = {
- 0, 0,
- 0, 1,
- 1, 0,
- 1, 1
- };
- fMipmapProgramArrayBuffer = GrGLBuffer::Make(this, sizeof(vdata), GrGpuBufferType::kVertex,
- kStatic_GrAccessPattern, vdata);
- }
- if (!fMipmapProgramArrayBuffer) {
- return false;
- }
- fHWVertexArrayState.setVertexArrayID(this, 0);
- GrGLAttribArrayState* attribs = fHWVertexArrayState.bindInternalVertexArray(this);
- attribs->enableVertexArrays(this, 1);
- attribs->set(this, 0, fMipmapProgramArrayBuffer.get(), kFloat2_GrVertexAttribType,
- kFloat2_GrSLType, 2 * sizeof(GrGLfloat), 0);
- // Set "simple" state once:
- this->flushBlendAndColorWrite(GrXferProcessor::BlendInfo(), GrSwizzle::RGBA());
- this->flushHWAAState(nullptr, false);
- this->disableScissor();
- this->disableWindowRectangles();
- this->disableStencil();
- // Do all the blits:
- width = texture->width();
- height = texture->height();
- for (GrGLint level = 1; level < levelCount; ++level) {
- // Get and bind the program for this particular downsample (filter shape can vary):
- int progIdx = TextureSizeToMipmapProgramIdx(width, height);
- if (!fMipmapPrograms[progIdx].fProgram) {
- if (!this->createMipmapProgram(progIdx)) {
- SkDebugf("Failed to create mipmap program.\n");
- // Invalidate all params to cover base level change in a previous iteration.
- glTex->textureParamsModified();
- return false;
- }
- }
- this->flushProgram(fMipmapPrograms[progIdx].fProgram);
- // Texcoord uniform is expected to contain (1/w, (w-1)/w, 1/h, (h-1)/h)
- const float invWidth = 1.0f / width;
- const float invHeight = 1.0f / height;
- GL_CALL(Uniform4f(fMipmapPrograms[progIdx].fTexCoordXformUniform,
- invWidth, (width - 1) * invWidth, invHeight, (height - 1) * invHeight));
- GL_CALL(Uniform1i(fMipmapPrograms[progIdx].fTextureUniform, 0));
- // Only sample from previous mip
- GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_BASE_LEVEL, level - 1));
- GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0, GR_GL_TEXTURE_2D,
- glTex->textureID(), level));
- width = SkTMax(1, width / 2);
- height = SkTMax(1, height / 2);
- this->flushViewport(width, height);
- GL_CALL(DrawArrays(GR_GL_TRIANGLE_STRIP, 0, 4));
- }
- // Unbind:
- GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0,
- GR_GL_TEXTURE_2D, 0, 0));
- // We modified the base level param.
- GrGLTextureParameters::NonsamplerState nonsamplerState = glTex->parameters()->nonsamplerState();
- // We drew the 2nd to last level into the last level.
- nonsamplerState.fBaseMipMapLevel = levelCount - 2;
- glTex->parameters()->set(nullptr, nonsamplerState, fResetTimestampForTextureParameters);
- return true;
- }
- void GrGLGpu::querySampleLocations(
- GrRenderTarget* renderTarget, SkTArray<SkPoint>* sampleLocations) {
- this->flushRenderTargetNoColorWrites(static_cast<GrGLRenderTarget*>(renderTarget));
- int effectiveSampleCnt;
- GR_GL_GetIntegerv(this->glInterface(), GR_GL_SAMPLES, &effectiveSampleCnt);
- SkASSERT(effectiveSampleCnt >= renderTarget->numSamples());
- sampleLocations->reset(effectiveSampleCnt);
- for (int i = 0; i < effectiveSampleCnt; ++i) {
- GL_CALL(GetMultisamplefv(GR_GL_SAMPLE_POSITION, i, &(*sampleLocations)[i].fX));
- }
- }
- void GrGLGpu::xferBarrier(GrRenderTarget* rt, GrXferBarrierType type) {
- SkASSERT(type);
- switch (type) {
- case kTexture_GrXferBarrierType: {
- GrGLRenderTarget* glrt = static_cast<GrGLRenderTarget*>(rt);
- SkASSERT(glrt->textureFBOID() != 0 && glrt->renderFBOID() != 0);
- if (glrt->textureFBOID() != glrt->renderFBOID()) {
- // The render target uses separate storage so no need for glTextureBarrier.
- // FIXME: The render target will resolve automatically when its texture is bound,
- // but we could resolve only the bounds that will be read if we do it here instead.
- return;
- }
- SkASSERT(this->caps()->textureBarrierSupport());
- GL_CALL(TextureBarrier());
- return;
- }
- case kBlend_GrXferBarrierType:
- SkASSERT(GrCaps::kAdvanced_BlendEquationSupport ==
- this->caps()->blendEquationSupport());
- GL_CALL(BlendBarrier());
- return;
- default: break; // placate compiler warnings that kNone not handled
- }
- }
- static GrPixelConfig gl_format_to_pixel_config(GrGLFormat format) {
- switch (format) {
- case GrGLFormat::kRGBA8: return kRGBA_8888_GrPixelConfig;
- case GrGLFormat::kRGB8: return kRGB_888_GrPixelConfig;
- case GrGLFormat::kRG8: return kRG_88_GrPixelConfig;
- case GrGLFormat::kBGRA8: return kBGRA_8888_GrPixelConfig;
- case GrGLFormat::kLUMINANCE8: return kGray_8_GrPixelConfig;
- case GrGLFormat::kSRGB8_ALPHA8: return kSRGBA_8888_GrPixelConfig;
- case GrGLFormat::kRGB10_A2: return kRGBA_1010102_GrPixelConfig;
- case GrGLFormat::kRGB565: return kRGB_565_GrPixelConfig;
- case GrGLFormat::kRGBA4: return kRGBA_4444_GrPixelConfig;
- case GrGLFormat::kRGBA32F: return kRGBA_float_GrPixelConfig;
- case GrGLFormat::kRGBA16F: return kRGBA_half_GrPixelConfig;
- case GrGLFormat::kR16: return kR_16_GrPixelConfig;
- case GrGLFormat::kRG16: return kRG_1616_GrPixelConfig;
- case GrGLFormat::kRGBA16: return kRGBA_16161616_GrPixelConfig;
- case GrGLFormat::kRG16F: return kRG_half_GrPixelConfig;
- case GrGLFormat::kUnknown: return kUnknown_GrPixelConfig;
- // Configs with multiple equivalent formats.
- case GrGLFormat::kR16F: return kAlpha_half_GrPixelConfig;
- case GrGLFormat::kLUMINANCE16F: return kAlpha_half_GrPixelConfig;
- case GrGLFormat::kALPHA8: return kAlpha_8_GrPixelConfig;
- case GrGLFormat::kR8: return kAlpha_8_GrPixelConfig;
- case GrGLFormat::kCOMPRESSED_RGB8_ETC2: return kRGB_ETC1_GrPixelConfig;
- case GrGLFormat::kCOMPRESSED_ETC1_RGB8: return kRGB_ETC1_GrPixelConfig;
- }
- SkUNREACHABLE;
- }
- GrBackendTexture GrGLGpu::createBackendTexture(int w, int h,
- const GrBackendFormat& format,
- GrMipMapped mipMapped,
- GrRenderable renderable,
- const void* srcPixels, size_t rowBytes,
- const SkColor4f* color,
- GrProtected isProtected) {
- this->handleDirtyContext();
- GrGLFormat glFormat = GrGLBackendFormatToGLFormat(format);
- if (glFormat == GrGLFormat::kUnknown) {
- return GrBackendTexture(); // invalid
- }
- GrPixelConfig config = gl_format_to_pixel_config(glFormat);
- if (config == kUnknown_GrPixelConfig) {
- return GrBackendTexture(); // invalid
- }
- if (!this->caps()->isConfigTexturable(config)) {
- return GrBackendTexture(); // invalid
- }
- if (w < 1 || w > this->caps()->maxTextureSize() ||
- h < 1 || h > this->caps()->maxTextureSize()) {
- return GrBackendTexture(); // invalid
- }
- // Currently we don't support uploading pixel data when mipped.
- if (srcPixels && GrMipMapped::kYes == mipMapped) {
- return GrBackendTexture(); // invalid
- }
- if (mipMapped == GrMipMapped::kYes && !this->caps()->mipMapSupport()) {
- return GrBackendTexture(); // invalid
- }
- GrGLTextureInfo info;
- GrGLTextureParameters::SamplerOverriddenState initialState;
- int mipLevelCount = 0;
- SkAutoTMalloc<GrMipLevel> texels;
- SkAutoMalloc pixelStorage;
- SkImage::CompressionType compressionType;
- if (GrGLFormatToCompressionType(glFormat, &compressionType)) {
- // Compressed textures currently must be non-MIP mapped and have initial data.
- if (mipMapped == GrMipMapped::kYes) {
- return GrBackendTexture();
- }
- if (!srcPixels) {
- if (!color) {
- return GrBackendTexture();
- }
- SkASSERT(0 == rowBytes);
- size_t size = GrCompressedDataSize(compressionType, w, h);
- srcPixels = pixelStorage.reset(size);
- GrFillInCompressedData(compressionType, w, h, (char*)srcPixels, *color);
- }
- if (!this->createCompressedTextureImpl(&info, w, h, compressionType, &initialState,
- srcPixels)) {
- return GrBackendTexture();
- }
- } else {
- if (srcPixels) {
- mipLevelCount = 1;
- texels.reset(mipLevelCount);
- texels.get()[0] = {srcPixels, rowBytes};
- } else if (color) {
- mipLevelCount = 1;
- if (GrMipMapped::kYes == mipMapped) {
- mipLevelCount = SkMipMap::ComputeLevelCount(w, h) + 1;
- }
- texels.reset(mipLevelCount);
- SkTArray<size_t> individualMipOffsets(mipLevelCount);
- size_t bytesPerPixel = GrBytesPerPixel(config);
- size_t totalSize = GrComputeTightCombinedBufferSize(
- bytesPerPixel, w, h, &individualMipOffsets, mipLevelCount);
- char* tmpPixels = (char*)pixelStorage.reset(totalSize);
- GrFillInData(config, w, h, individualMipOffsets, tmpPixels, *color);
- for (int i = 0; i < mipLevelCount; ++i) {
- size_t offset = individualMipOffsets[i];
- int twoToTheMipLevel = 1 << i;
- int currentWidth = SkTMax(1, w / twoToTheMipLevel);
- texels.get()[i] = {&(tmpPixels[offset]), currentWidth * bytesPerPixel};
- }
- }
- GrSurfaceDesc desc;
- desc.fWidth = w;
- desc.fHeight = h;
- desc.fConfig = config;
- if (!this->createTextureImpl(desc, &info, renderable, &initialState, texels.get(),
- mipLevelCount, nullptr)) {
- return GrBackendTexture(); // invalid
- }
- }
- // unbind the texture from the texture unit to avoid asserts
- GL_CALL(BindTexture(info.fTarget, 0));
- auto parameters = sk_make_sp<GrGLTextureParameters>();
- parameters->set(&initialState, GrGLTextureParameters::NonsamplerState(),
- fResetTimestampForTextureParameters);
- GrBackendTexture beTex = GrBackendTexture(w, h, mipMapped, info, std::move(parameters));
- #if GR_TEST_UTILS
- // Lots of tests don't go through Skia's public interface, which will set the config, so for
- // testing we make sure we set a config here.
- beTex.setPixelConfig(config);
- #endif
- return beTex;
- }
- void GrGLGpu::deleteBackendTexture(const GrBackendTexture& tex) {
- SkASSERT(GrBackendApi::kOpenGL == tex.backend());
- GrGLTextureInfo info;
- if (tex.getGLTextureInfo(&info)) {
- GL_CALL(DeleteTextures(1, &info.fID));
- }
- }
- #if GR_TEST_UTILS
- bool GrGLGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
- SkASSERT(GrBackendApi::kOpenGL == tex.backend());
- GrGLTextureInfo info;
- if (!tex.getGLTextureInfo(&info)) {
- return false;
- }
- GrGLboolean result;
- GL_CALL_RET(result, IsTexture(info.fID));
- return (GR_GL_TRUE == result);
- }
- GrBackendRenderTarget GrGLGpu::createTestingOnlyBackendRenderTarget(int w, int h,
- GrColorType colorType) {
- if (w > this->caps()->maxRenderTargetSize() || h > this->caps()->maxRenderTargetSize()) {
- return GrBackendRenderTarget(); // invalid
- }
- this->handleDirtyContext();
- auto config = GrColorTypeToPixelConfig(colorType);
- if (!this->glCaps().isConfigRenderable(config)) {
- return {};
- }
- auto format = this->glCaps().getFormatFromColorType(colorType);
- bool useTexture = false;
- GrGLenum colorBufferFormat;
- GrGLenum externalFormat = 0, externalType = 0;
- if (config == kBGRA_8888_GrPixelConfig && this->glCaps().bgraIsInternalFormat()) {
- // BGRA render buffers are not supported.
- this->glCaps().getTexImageFormats(config, config, &colorBufferFormat, &externalFormat,
- &externalType);
- useTexture = true;
- } else {
- colorBufferFormat = this->glCaps().getRenderbufferInternalFormat(format);
- }
- int sFormatIdx = this->getCompatibleStencilIndex(format);
- if (sFormatIdx < 0) {
- return {};
- }
- GrGLuint colorID = 0;
- GrGLuint stencilID = 0;
- auto deleteIDs = [&] {
- if (colorID) {
- if (useTexture) {
- GL_CALL(DeleteTextures(1, &colorID));
- } else {
- GL_CALL(DeleteRenderbuffers(1, &colorID));
- }
- }
- if (stencilID) {
- GL_CALL(DeleteRenderbuffers(1, &stencilID));
- }
- };
- if (useTexture) {
- GL_CALL(GenTextures(1, &colorID));
- } else {
- GL_CALL(GenRenderbuffers(1, &colorID));
- }
- GL_CALL(GenRenderbuffers(1, &stencilID));
- if (!stencilID || !colorID) {
- deleteIDs();
- return {};
- }
- GrGLFramebufferInfo info;
- info.fFBOID = 0;
- info.fFormat = this->glCaps().configSizedInternalFormat(config);
- GL_CALL(GenFramebuffers(1, &info.fFBOID));
- if (!info.fFBOID) {
- deleteIDs();
- return {};
- }
- this->invalidateBoundRenderTarget();
- this->bindFramebuffer(GR_GL_FRAMEBUFFER, info.fFBOID);
- if (useTexture) {
- this->bindTextureToScratchUnit(GR_GL_TEXTURE_2D, colorID);
- GL_CALL(TexImage2D(GR_GL_TEXTURE_2D, 0, colorBufferFormat, w, h, 0, externalFormat,
- externalType, nullptr));
- GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0, GR_GL_TEXTURE_2D,
- colorID, 0));
- } else {
- GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, colorID));
- GL_ALLOC_CALL(this->glInterface(),
- RenderbufferStorage(GR_GL_RENDERBUFFER, colorBufferFormat, w, h));
- GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0,
- GR_GL_RENDERBUFFER, colorID));
- }
- GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, stencilID));
- auto stencilBufferFormat = this->glCaps().stencilFormats()[sFormatIdx].fInternalFormat;
- GL_ALLOC_CALL(this->glInterface(),
- RenderbufferStorage(GR_GL_RENDERBUFFER, stencilBufferFormat, w, h));
- GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_STENCIL_ATTACHMENT, GR_GL_RENDERBUFFER,
- stencilID));
- if (this->glCaps().stencilFormats()[sFormatIdx].fPacked) {
- GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_DEPTH_ATTACHMENT,
- GR_GL_RENDERBUFFER, stencilID));
- }
- // We don't want to have to recover the renderbuffer/texture IDs later to delete them. OpenGL
- // has this rule that if a renderbuffer/texture is deleted and a FBO other than the current FBO
- // has the RB attached then deletion is delayed. So we unbind the FBO here and delete the
- // renderbuffers/texture.
- this->bindFramebuffer(GR_GL_FRAMEBUFFER, 0);
- deleteIDs();
- this->bindFramebuffer(GR_GL_FRAMEBUFFER, info.fFBOID);
- GrGLenum status;
- GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
- if (GR_GL_FRAMEBUFFER_COMPLETE != status) {
- this->deleteFramebuffer(info.fFBOID);
- return {};
- }
- auto stencilBits = SkToInt(this->glCaps().stencilFormats()[sFormatIdx].fStencilBits);
- GrBackendRenderTarget beRT = GrBackendRenderTarget(w, h, 1, stencilBits, info);
- // Lots of tests don't go through Skia's public interface which will set the config so for
- // testing we make sure we set a config here.
- beRT.setPixelConfig(config);
- SkASSERT(kUnknown_GrPixelConfig != this->caps()->validateBackendRenderTarget(beRT, colorType));
- return beRT;
- }
- void GrGLGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget& backendRT) {
- SkASSERT(GrBackendApi::kOpenGL == backendRT.backend());
- GrGLFramebufferInfo info;
- if (backendRT.getGLFramebufferInfo(&info)) {
- if (info.fFBOID) {
- this->deleteFramebuffer(info.fFBOID);
- }
- }
- }
- void GrGLGpu::testingOnly_flushGpuAndSync() {
- GL_CALL(Finish());
- }
- #endif
- ///////////////////////////////////////////////////////////////////////////////
- GrGLAttribArrayState* GrGLGpu::HWVertexArrayState::bindInternalVertexArray(GrGLGpu* gpu,
- const GrBuffer* ibuf) {
- GrGLAttribArrayState* attribState;
- if (gpu->glCaps().isCoreProfile()) {
- if (!fCoreProfileVertexArray) {
- GrGLuint arrayID;
- GR_GL_CALL(gpu->glInterface(), GenVertexArrays(1, &arrayID));
- int attrCount = gpu->glCaps().maxVertexAttributes();
- fCoreProfileVertexArray = new GrGLVertexArray(arrayID, attrCount);
- }
- if (ibuf) {
- attribState = fCoreProfileVertexArray->bindWithIndexBuffer(gpu, ibuf);
- } else {
- attribState = fCoreProfileVertexArray->bind(gpu);
- }
- } else {
- if (ibuf) {
- // bindBuffer implicitly binds VAO 0 when binding an index buffer.
- gpu->bindBuffer(GrGpuBufferType::kIndex, ibuf);
- } else {
- this->setVertexArrayID(gpu, 0);
- }
- int attrCount = gpu->glCaps().maxVertexAttributes();
- if (fDefaultVertexArrayAttribState.count() != attrCount) {
- fDefaultVertexArrayAttribState.resize(attrCount);
- }
- attribState = &fDefaultVertexArrayAttribState;
- }
- return attribState;
- }
- void GrGLGpu::onFinishFlush(GrSurfaceProxy*[], int, SkSurface::BackendSurfaceAccess access,
- const GrFlushInfo& info, const GrPrepareForExternalIORequests&) {
- // If we inserted semaphores during the flush, we need to call GLFlush.
- bool insertedSemaphore = info.fNumSemaphores > 0 && this->caps()->semaphoreSupport();
- // We call finish if the client told us to sync or if we have a finished proc but don't support
- // GLsync objects.
- bool finish = (info.fFlags & kSyncCpu_GrFlushFlag) ||
- (info.fFinishedProc && !this->caps()->fenceSyncSupport());
- if (finish) {
- GL_CALL(Finish());
- // After a finish everything previously sent to GL is done.
- for (const auto& cb : fFinishCallbacks) {
- cb.fCallback(cb.fContext);
- this->deleteSync(cb.fSync);
- }
- fFinishCallbacks.clear();
- if (info.fFinishedProc) {
- info.fFinishedProc(info.fFinishedContext);
- }
- } else {
- if (info.fFinishedProc) {
- FinishCallback callback;
- callback.fCallback = info.fFinishedProc;
- callback.fContext = info.fFinishedContext;
- callback.fSync = (GrGLsync)this->insertFence();
- fFinishCallbacks.push_back(callback);
- GL_CALL(Flush());
- } else if (insertedSemaphore) {
- // Must call flush after semaphores in case they are waited on another GL context.
- GL_CALL(Flush());
- }
- // See if any previously inserted finish procs are good to go.
- this->checkFinishProcs();
- }
- }
- void GrGLGpu::submit(GrGpuCommandBuffer* buffer) {
- if (buffer->asRTCommandBuffer()) {
- SkASSERT(fCachedRTCommandBuffer.get() == buffer);
- fCachedRTCommandBuffer->reset();
- } else {
- SkASSERT(fCachedTexCommandBuffer.get() == buffer);
- fCachedTexCommandBuffer->reset();
- }
- }
- GrFence SK_WARN_UNUSED_RESULT GrGLGpu::insertFence() {
- SkASSERT(this->caps()->fenceSyncSupport());
- GrGLsync sync;
- GL_CALL_RET(sync, FenceSync(GR_GL_SYNC_GPU_COMMANDS_COMPLETE, 0));
- GR_STATIC_ASSERT(sizeof(GrFence) >= sizeof(GrGLsync));
- return (GrFence)sync;
- }
- bool GrGLGpu::waitSync(GrGLsync sync, uint64_t timeout, bool flush) {
- GrGLbitfield flags = flush ? GR_GL_SYNC_FLUSH_COMMANDS_BIT : 0;
- GrGLenum result;
- GL_CALL_RET(result, ClientWaitSync(sync, flags, timeout));
- return (GR_GL_CONDITION_SATISFIED == result || GR_GL_ALREADY_SIGNALED == result);
- }
- bool GrGLGpu::waitFence(GrFence fence, uint64_t timeout) {
- return this->waitSync((GrGLsync)fence, timeout, /* flush = */ true);
- }
- void GrGLGpu::deleteFence(GrFence fence) const {
- this->deleteSync((GrGLsync)fence);
- }
- sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrGLGpu::makeSemaphore(bool isOwned) {
- SkASSERT(this->caps()->semaphoreSupport());
- return GrGLSemaphore::Make(this, isOwned);
- }
- sk_sp<GrSemaphore> GrGLGpu::wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
- GrResourceProvider::SemaphoreWrapType wrapType,
- GrWrapOwnership ownership) {
- SkASSERT(this->caps()->semaphoreSupport());
- return GrGLSemaphore::MakeWrapped(this, semaphore.glSync(), ownership);
- }
- void GrGLGpu::insertSemaphore(sk_sp<GrSemaphore> semaphore) {
- GrGLSemaphore* glSem = static_cast<GrGLSemaphore*>(semaphore.get());
- GrGLsync sync;
- GL_CALL_RET(sync, FenceSync(GR_GL_SYNC_GPU_COMMANDS_COMPLETE, 0));
- glSem->setSync(sync);
- }
- void GrGLGpu::waitSemaphore(sk_sp<GrSemaphore> semaphore) {
- GrGLSemaphore* glSem = static_cast<GrGLSemaphore*>(semaphore.get());
- GL_CALL(WaitSync(glSem->sync(), 0, GR_GL_TIMEOUT_IGNORED));
- }
- void GrGLGpu::checkFinishProcs() {
- // Bail after the first unfinished sync since we expect they signal in the order inserted.
- while (!fFinishCallbacks.empty() && this->waitSync(fFinishCallbacks.front().fSync,
- /* timeout = */ 0, /* flush = */ false)) {
- fFinishCallbacks.front().fCallback(fFinishCallbacks.front().fContext);
- this->deleteSync(fFinishCallbacks.front().fSync);
- fFinishCallbacks.pop_front();
- }
- }
- void GrGLGpu::deleteSync(GrGLsync sync) const {
- GL_CALL(DeleteSync(sync));
- }
- void GrGLGpu::insertEventMarker(const char* msg) {
- GL_CALL(InsertEventMarker(strlen(msg), msg));
- }
- sk_sp<GrSemaphore> GrGLGpu::prepareTextureForCrossContextUsage(GrTexture* texture) {
- // Set up a semaphore to be signaled once the data is ready, and flush GL
- sk_sp<GrSemaphore> semaphore = this->makeSemaphore(true);
- this->insertSemaphore(semaphore);
- // We must call flush here to make sure the GrGLSync object gets created and sent to the gpu.
- GL_CALL(Flush());
- return semaphore;
- }
- int GrGLGpu::TextureToCopyProgramIdx(GrTexture* texture) {
- switch (GrSLCombinedSamplerTypeForTextureType(texture->texturePriv().textureType())) {
- case kTexture2DSampler_GrSLType:
- return 0;
- case kTexture2DRectSampler_GrSLType:
- return 1;
- case kTextureExternalSampler_GrSLType:
- return 2;
- default:
- SK_ABORT("Unexpected samper type");
- return 0;
- }
- }
- #ifdef SK_ENABLE_DUMP_GPU
- #include "src/utils/SkJSONWriter.h"
- void GrGLGpu::onDumpJSON(SkJSONWriter* writer) const {
- // We are called by the base class, which has already called beginObject(). We choose to nest
- // all of our caps information in a named sub-object.
- writer->beginObject("GL GPU");
- const GrGLubyte* str;
- GL_CALL_RET(str, GetString(GR_GL_VERSION));
- writer->appendString("GL_VERSION", (const char*)(str));
- GL_CALL_RET(str, GetString(GR_GL_RENDERER));
- writer->appendString("GL_RENDERER", (const char*)(str));
- GL_CALL_RET(str, GetString(GR_GL_VENDOR));
- writer->appendString("GL_VENDOR", (const char*)(str));
- GL_CALL_RET(str, GetString(GR_GL_SHADING_LANGUAGE_VERSION));
- writer->appendString("GL_SHADING_LANGUAGE_VERSION", (const char*)(str));
- writer->appendName("extensions");
- glInterface()->fExtensions.dumpJSON(writer);
- writer->endObject();
- }
- #endif
|