WebGL best practices - Web APIs | MDN

文章推薦指數: 80 %
投票人數:10人

WebGL is a complicated API, and it's often not obvious what the recommended ways to use it are. This page tackles recommendations across the ... SkiptomaincontentSkiptosearchSkiptoselectlanguageReferencesWebAPIsWebGL:2Dand3DgraphicsforthewebWebGLbestpracticesArticleActionsEnglish(US)AddressandeliminateWebGLerrorsUnderstandextensionavailabilityUnderstandsystemlimitsAvoidinvalidatingFBOattachmentbindingsDeleteobjectseagerlyLosecontextseagerlyFlushwhenexpectingresultsAvoidblockingAPIcallsinproductionAlwaysenablevertexattrib0asanarrayEstimateaper-pixelVRAMBudgetConsiderrenderingtoasmallerbackbufferBatchdrawcallsAvoid"#ifdefGL_ES"PreferdoingworkinthevertexshaderCompileShadersandLinkProgramsinparallelPreferKHR_parallel_shader_compileDon'tcheckshadercompilestatusunlesslinkingfailsBeprecisewithGLSLprecisionannotationsPreferbuiltinsinsteadofbuildingyourownUsemipmapsforanytextureyou'llseein3dDon'tassumeyoucanrenderintofloattexturesSomeformats(e.g.RGB)maybeemulatedAvoidalpha:false,whichcanbeexpensiveConsidercompressedtextureformatsMemoryusageofdepthandstencilformatstexImage/texSubImageuploads(esp.videos)cancausepipelineflushesUsetexStoragetocreatetexturesUseinvalidateFramebufferUsenon-blockingasyncdatareadbackImageBitmapcreationRelatedTopics WebGLAPI WebGLtutorial GettingstartedwithWebGL Adding2DcontenttoaWebGLcontext UsingshaderstoapplycolorinWebGL AnimatingobjectswithWebGL Creating3DobjectsusingWebGL UsingtexturesinWebGL LightinginWebGL AnimatingtexturesinWebGL Examplesandarticles Matrixmathfortheweb WebGLmodelviewprojection WebGLbestpractices UsingWebGLextensions Abasic2DWebGLanimationexample WebGLbyexample Interfaces WebGLRenderingContext WebGL2RenderingContext WebGLActiveInfo WebGLBuffer WebGLContextEvent WebGLFramebuffer WebGLProgram WebGLQuery WebGLRenderbuffer WebGLSampler WebGLShader WebGLShaderPrecisionFormat WebGLSync WebGLTexture WebGLTransformFeedback WebGLUniformLocation WebGLVertexArrayObject Documentation: Contribute TheMDNproject AddressandeliminateWebGLerrorsUnderstandextensionavailabilityUnderstandsystemlimitsAvoidinvalidatingFBOattachmentbindingsDeleteobjectseagerlyLosecontextseagerlyFlushwhenexpectingresultsAvoidblockingAPIcallsinproductionAlwaysenablevertexattrib0asanarrayEstimateaper-pixelVRAMBudgetConsiderrenderingtoasmallerbackbufferBatchdrawcallsAvoid"#ifdefGL_ES"PreferdoingworkinthevertexshaderCompileShadersandLinkProgramsinparallelPreferKHR_parallel_shader_compileDon'tcheckshadercompilestatusunlesslinkingfailsBeprecisewithGLSLprecisionannotationsPreferbuiltinsinsteadofbuildingyourownUsemipmapsforanytextureyou'llseein3dDon'tassumeyoucanrenderintofloattexturesSomeformats(e.g.RGB)maybeemulatedAvoidalpha:false,whichcanbeexpensiveConsidercompressedtextureformatsMemoryusageofdepthandstencilformatstexImage/texSubImageuploads(esp.videos)cancausepipelineflushesUsetexStoragetocreatetexturesUseinvalidateFramebufferUsenon-blockingasyncdatareadbackImageBitmapcreationWebGLbestpracticesWebGLisacomplicatedAPI,andit'softennotobviouswhattherecommendedwaystouseitare.Thispagetacklesrecommendationsacrossthespectrumofexpertise,andnotonlyhighlightsdosanddon'ts,butalsodetailswhy.Youcanrelyonthisdocumenttoguideyourchoiceofapproach,andensureyou'reontherighttracknomatterwhatbrowserorhardwareyourusersrun.AddressandeliminateWebGLerrorsYourapplicationshouldrunwithoutgeneratinganyWebGLerrors(asreturnedbygetError).EveryWebGLerrorisreportedintheWebConsoleasaJavaScriptwarningwithadescriptivemessage.Aftertoomanyerrors(32inFirefox),WebGLstopsgeneratingdescriptivemessages,whichreallyhindersdebugging. Theonlyerrorsawell-formedpagegeneratesareOUT_OF_MEMORYandCONTEXT_LOST.UnderstandextensionavailabilityTheavailabilityofmostWebGLextensionsdependsontheclientsystem.WhenusingWebGLextensions,ifpossible,trytomakethemoptionalbygracefullyadaptingtothecasetheretheyarenotsupported. TheseWebGL1extensionsareuniversallysupported,andcanbereliedupontobepresent: ANGLE_instanced_arrays EXT_blend_minmax OES_element_index_uint OES_standard_derivatives OES_vertex_array_object WEBGL_debug_renderer_info WEBGL_lose_context (seealso:https://jdashg.github.io/misc/webgl/webgl-feature-levels.html) ConsiderpolyfillingtheseintoWebGLRenderingContext,like:https://github.com/jdashg/misc/blob/master/webgl/webgl-v1.1.jsUnderstandsystemlimitsSimilarlytoextensions,thelimitsofyoursystemwillbedifferentthanyourclients'systems!Don'tassumeyoucanusethirtytexturesamplerspershaderjustbecauseitworksonyourmachine! TheminimumrequirementsforWebGLarequitelow.Inpractice,effectivelyallsystemssupportatleastthefollowing: MAX_CUBE_MAP_TEXTURE_SIZE:4096 MAX_RENDERBUFFER_SIZE:4096 MAX_TEXTURE_SIZE:4096 MAX_VIEWPORT_DIMS:[4096,4096] MAX_VERTEX_TEXTURE_IMAGE_UNITS:4 MAX_TEXTURE_IMAGE_UNITS:8 MAX_COMBINED_TEXTURE_IMAGE_UNITS:8 MAX_VERTEX_ATTRIBS:16 MAX_VARYING_VECTORS:8 MAX_VERTEX_UNIFORM_VECTORS:128 MAX_FRAGMENT_UNIFORM_VECTORS:64 ALIASED_POINT_SIZE_RANGE:[1,100] Yourdesktopmaysupport16ktextures,ormaybe16textureunitsinthevertexshader,butmostothersystemsdon't,andcontentthatworksforyouwillnotworkforthem!AvoidinvalidatingFBOattachmentbindingsAlmostanychangetoanFBO'sattachmentbindingswillinvalidateitsframebuffercompleteness.Setupyourhotframebuffersaheadoftime. InFirefox,settingtheprefwebgl.perf.max-warningsto-1inabout:configwillenableperformancewarningsthatincludewarningsaboutFBcompletenessinvalidations.AvoidchangingVAOattachments(vertexAttribPointer,disable/enableVertexAttribArray)Drawingfromstatic,unchangingVAOsisfasterthanmutatingthesameVAOforeverydrawcall.ForunchangedVAOs,browserscancachethefetchlimits,whereaswhenVAOschange,browsersmustrevalidateandrecalculatelimits.Theoverheadforthisisrelativelylow,butre-usingVAOsmeansfewervertexAttribPointercallstoo,soit'sworthdoingwhereverit'seasy.DeleteobjectseagerlyDon'twaitforthegarbagecollector/cyclecollectortorealizeobjectsareorphanedanddestroythem.Implementationstrackthelivenessofobjects,so'deleting'themattheAPIlevelonlyreleasesthehandlethatreferstotheactualobject.(conceptuallyreleasingthehandle'sref-pointertotheobject)Onlyoncetheobjectisunusedintheimplementationisitactuallyfreed.Forexample,ifyouneverwanttoaccessyourshaderobjectsdirectlyagain,justdeletetheirhandlesafterattachingthemtoaprogramobject.LosecontextseagerlyConsideralsoeagerlylosingWebGLcontextsviatheWEBGL_lose_contextextensionwhenyou'redefinitelydonewiththemandnolongerneedthetargetcanvas'srenderingresults.Notethatthisisnotnecessarytodowhennavigatingawayfromapage-don'taddanunloadeventhandlerjustforthispurpose.FlushwhenexpectingresultsCallflush()whenexpectingresultssuchasqueries,oratcompletionofarenderingframe. Flushtellstheimplementationtopushallpendingcommandsoutforexecution,flushingthemoutofthequeue,insteadofwaitingformorecommandstoenqueuebeforesendingforexecution. Forexample,itispossibleforthefollowingtonevercompletewithoutcontextloss: sync=glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE,0); glClientWaitSync(sync,0,GL_TIMEOUT_IGNORED); WebGLdoesn'thaveaSwapBufferscallbydefault,soaflushcanhelpfillthegap,aswell.Usewebgl.flush()whennotusingrequestAnimationFrameWhennotusingRAF,(suchaswhenusingRPAF;seebelow)usewebgl.flush()toencourageeagerexecutionofenqueuedcommands. BecauseRAFisdirectlyfollowedbytheframeboundary,anexplicitwebgl.flush()isn'treallyneededwithRAF.AvoidblockingAPIcallsinproductionCertainWebGLentrypoints-includinggetErrorandgetParameter-causesynchronousstallsonthecallingthread.Evenbasicrequestscantakeaslongas1ms,buttheycantakeevenlongeriftheyneedtowaitforallgraphicsworktobecompleted(withaneffectsimilartoglFinish()innativeOpenGL). Inproductioncode,avoidsuchentrypoints,especiallyonthebrowsermainthreadwheretheycancausetheentirepagetojank(oftenincludingscrollingoreventhewholebrowser). getError():causesaflush+round-triptofetcherrorsfromtheGPUprocess). Forexample,withinFirefox,theonlytimeglGetErrorischeckedisafterallocations(bufferData,*texImage*,texStorage*)topickupanyGL_OUT_OF_MEMORYerrors. getShader/ProgramParameter(),getShader/ProgramInfoLog(),othergetsonshaders/programs:flush+shadercompile+round-trip,ifnotdoneaftershadercompilationiscomplete.(Seealsoparallelshadercompilationbelow.) get*Parameter()ingeneral:possibleflush+round-trip.Insomecases,thesewillbecachedtoavoidtheround-trip,buttrytoavoidrelyingonthis. checkFramebufferStatus():possibleflush+round-trip. getBufferSubData():usualfinish+round-trip.(ThisisokayforREADbuffersinconjunctionwithfences-seeasyncdatareadbackbelow.) readPixels()totheCPU(i.e.withoutanUNPACKbufferbound):finish+round-trip.Instead,useGPU-GPUreadPixelsinconjunctionwithasyncdatareadback. Alwaysenablevertexattrib0asanarrayIfyoudrawwithoutvertexattrib0enabledasanarray,youwillforcethebrowsertodocomplicatedemulationwhenrunningondesktopOpenGL(suchasonmacOS).ThisisbecauseindesktopOpenGL,nothinggetsdrawnifvertexattrib0isnotarray-enabled.YoucanusebindAttribLocationtoforceavertexattributetouselocation0,anduseenableVertexAttribArray(0)tomakeitarray-enabled.Estimateaper-pixelVRAMBudgetWebGLdoesn'tofferAPIstoquerythemaximumamountofvideomemoryonthesystembecausesuchqueriesarenotportable.Still,applicationsmustbeconsciousofVRAMusageandnotjustallocateasmuchaspossible. OnetechniquepioneeredbytheGoogleMapsteamisthenotionofaper-pixelVRAMbudget: 1)Foronesystem(e.g.aparticulardesktop/laptop),decidethemaximumamountofVRAMyourapplicationshoulduse.2)Computethenumberofpixelscoveredbyamaximizedbrowserwindow.E.g.(window.innerWidth*devicePixelRatio)*(window.innerHeight*window.devicePixelRatio)3)Theper-pixelVRAMbudgetis(1)dividedby(2),andisaconstant. Thisconstantshouldgenerallybeportableamongsystems.Mobiledevicestypicallyhavesmallerscreensthanpowerfuldesktopmachineswithlargemonitors.Re-computethisconstantonafewtargetsystemstogetareliableestimate. Nowadjustallinternalcachingintheapplication(WebGLBuffers,WebGLTextures,etc.)toobeyamaximumsize,computedbythisconstantmultipliedbythenumberofpixelscoveredbythecurrentbrowserwindow.Thisrequiresestimatingthenumberofbytesconsumedbyeachtexture,forexample.Thecapalsomusttypicallybeupdatedasthebrowserwindowresizes,andolderresourcesabovethelimitmustbepurged. Keepingtheapplication'sVRAMusageunderthiscapwillhelptoavoidout-of-memoryerrorsandassociatedinstability.ConsiderrenderingtoasmallerbackbufferAcommon(andeasy)waytotradeoffqualityforspeedisrenderingintoasmallerbackbuffer,andupscalingtheresult.Considerreducingcanvas.widthandheightandkeepingcanvas.style.widthandheightataconstantsize.Batchdrawcalls"Batching"drawcallsintofewer,largerdrawcallswillgenerallyimproveperformance.Ifyouhave1000spritestopaint,trytodoitasasingledrawArrays()ordrawElements()call. It'scommontouse"degeneratetriangles"ifyouneedtodrawdiscontinuousobjectsasasingledrawArrays(TRIANGLE_STRIP)call.Degeneratetrianglesaretriangleswithnoarea,thereforeanytrianglewheremorethanonepointisinthesameexactlocation.Thesetrianglesareeffectivelyskipped,whichletsyoustartanewtrianglestripunattachedtoyourpreviousone,withouthavingtosplitintomultipledrawcalls. Anotherimportantmethodforbatchingistextureatlasing,wheremultipleimagesareplacedintoasingletexture,oftenlikeacheckerboard.Sinceyouneedtosplitdrawcallbatchestochangetextures,textureatlasingletsyoucombinemoredrawcallsintofewer,biggerbatches.Seethisexampledemonstratinghowtocombineevenspritesreferencingmultipletextureatlasesintoasingledrawcall.Avoid"#ifdefGL_ES"Youshouldneveruse#ifdefGL_ESinyourWebGLshaders;thisconditionisalwaystrueinWebGL.Althoughsomeearlyexamplesusedthis,it'snotnecessary.PreferdoingworkinthevertexshaderDoasmuchworkasyoucaninthevertexshader,ratherthaninthefragmentshader.Thisisbecauseperdrawcall,fragmentshadersgenerallyrunmanymoretimesthanvertexshaders.Anycalculationthatcanbedoneontheverticesandthenjustinterpolatedamongfragments(viavaryings)isaperformanceboon.(Theinterpolationofvaryingsisverycheap,andisdoneautomaticallyforyouthroughthefixedfunctionalityrasterizationphaseofthegraphicspipeline.) Forexample,asimpleanimationofatexturedsurfacecanbeachievedthroughatime-dependenttransformationoftexturecoordinates.(Thesimplestcasebeingaddingauniformvectortothetexturecoordinatesattributevector)Ifvisuallyacceptable,onecantransformthetexturecoordinatesinthevertexshaderratherthaninthefragmentshader,togetbetterperformance. Onecommontrade-offistosomelightingcalculationsper-vertexinsteadofper-fragment(pixel).Insomecases,especiallywithsimplemodelsordensevertices,thislooksgoodenough. Theinversionofthisisifamodelhasmoreverticesthanpixelsintherenderedoutput.However,LODmeshesisusuallytheanswertothisproblem,rarelymovingworkfromthevertextothefragmentshader.CompileShadersandLinkProgramsinparallelIt'stemptingtocompileshadersandlinkprogramsserially,butmanybrowserscancompileandlinkinparallelonbackgroundthreads. Insteadof: functioncompileOnce(gl,shader){ if(shader.compiled)return; gl.compileShader(shader); shader.compiled=true; } for(const[vs,fs,prog]ofprograms){ compileOnce(gl,vs); compileOnce(gl,fs); gl.linkProgram(prog); if(!gl.getProgramParameter(prog,gl.LINK_STATUS)){ console.error('Linkfailed:'+gl.getProgramInfoLog(prog)); console.error('vsinfo-log:'+gl.getShaderInfoLog(vs)); console.error('fsinfo-log:'+gl.getShaderInfoLog(fs)); } } Consider: functioncompileOnce(gl,shader){ if(shader.compiled)return; gl.compileShader(shader); shader.compiled=true; } for(const[vs,fs,prog]ofprograms){ compileOnce(gl,vs); compileOnce(gl,fs); } for(const[vs,fs,prog]ofprograms){ gl.linkProgram(prog); } for(const[vs,fs,prog]ofprograms){ if(!gl.getProgramParameter(prog,gl.LINK_STATUS)){ console.error('Linkfailed:'+gl.getProgramInfoLog(prog)); console.error('vsinfo-log:'+gl.getShaderInfoLog(vs)); console.error('fsinfo-log:'+gl.getShaderInfoLog(fs)); } } PreferKHR_parallel_shader_compileWhilewe'vedescribedapatterntoallowbrowserstocompileandlinkinparallel,normallycheckingCOMPILE_STATUSorLINK_STATUSblocksuntilthecompileorlinkcompletes.Inbrowserswhereit'savailable,theKHR_parallel_shader_compileextensionprovidesanon-blockingCOMPLETION_STATUSquery.Prefertoenableandusethisextension. Exampleusage: ext=gl.getExtension('KHR_parallel_shader_compile'); gl.compileProgram(vs); gl.compileProgram(fs); gl.attachShader(prog,vs); gl.attachShader(prog,fs); gl.linkProgram(prog); //Storeprograminyourdatastructure. //Later,forexamplethenextframe: if(ext){ if(gl.getProgramParameter(prog,ext.COMPLETION_STATUS_KHR)){ //Checkprogramlinkstatus;ifOK,useanddrawwithit. } }else{ //Programlinkingissynchronous. //Checkprogramlinkstatus;ifOK,useanddrawwithit. } Thistechniquemaynotworkinallapplications,forexamplethosewhichrequireprogramstobeimmediatelyavailableforrendering.Still,considerhowvariationsmaywork.Don'tcheckshadercompilestatusunlesslinkingfailsThereareveryfewerrorsthatareguaranteedtocauseshadercompilationfailure,butcannotbedeferredtolinktime.TheESSL3specsaysthisunder"ErrorHandling": Theimplementationshouldreporterrorsasearlyapossiblebutinanycasemustsatisfythefollowing: Alllexical,grammaticalandsemanticerrorsmusthavebeendetectedfollowingacalltoglLinkProgram Errorsduetomismatchbetweenthevertexandfragmentshader(linkerrors)musthavebeendetectedfollowingacalltoglLinkProgram ErrorsduetoexceedingresourcelimitsmusthavebeendetectedfollowinganydrawcalloracalltoglValidateProgram AcalltoglValidateProgrammustreportallerrorsassociatedwithaprogramobjectgiventhecurrentGLstate. Theallocationoftasksbetweenthecompilerandlinkerisimplementationdependent.Consequentlytherearemanyerrorswhichmaybedetectedeitheratcompileorlinktime,dependingontheimplementation. Additionally,queryingcompilestatusisasynchronouscall,whichbreakspipelining. Insteadof: gl.compileShader(vs); if(!gl.getShaderParameter(vs,gl.COMPILE_STATUS)){ console.error('vscompilefailed:'+gl.getShaderInfoLog(vs)); } gl.compileShader(fs); if(!gl.getShaderParameter(fs,gl.COMPILE_STATUS)){ console.error('fscompilefailed:'+gl.getShaderInfoLog(fs)); } gl.linkProgram(prog); if(!gl.getProgramParameter(vs,gl.LINK_STATUS)){ console.error('Linkfailed:'+gl.getProgramInfoLog(prog)); } Consider: gl.compileShader(vs); gl.compileShader(fs); gl.linkProgram(prog); if(!gl.getProgramParameter(vs,gl.LINK_STATUS)){ console.error('Linkfailed:'+gl.getProgramInfoLog(prog)); console.error('vsinfo-log:'+gl.getShaderInfoLog(vs)); console.error('fsinfo-log:'+gl.getShaderInfoLog(fs)); } BeprecisewithGLSLprecisionannotationsIfyouexpecttopassanessl300intbetweenshaders,andyouneedittohave32-bits,youmustusehighporyouwillhaveportabilityproblems.(WorksonDesktop,notonAndroid) Ifyouhaveafloattexture,iOSrequiresthatyouusehighpsampler2Dfoo;,oritwillverypainfullygiveyoulowptexturesamples!(+/-2.0maxisprobablynotgoodenoughforyou)ImplicitdefaultsThevertexlanguagehasthefollowingpredeclaredgloballyscopeddefaultprecisionstatements: precisionhighpfloat; precisionhighpint; precisionlowpsampler2D; precisionlowpsamplerCube; Thefragmentlanguagehasthefollowingpredeclaredgloballyscopeddefaultprecisionstatements: precisionmediumpint; precisionlowpsampler2D; precisionlowpsamplerCube; InWebGL1,"highpfloat"supportisoptionalinfragmentshadersUsinghighpprecisionunconditionallyinfragmentshaderswillpreventyourcontentfromworkingonsomeoldermobilehardware. Whileyoucanusemediumpfloatinstead,butbeawarethatthisoftenresultsincorruptedrenderingduetolackofprecision(particularlymobilesystems)thoughthecorruptionisnotgoingtobevisibleonatypicaldesktopcomputer. Ifyouknowyourprecisionrequirements,getShaderPrecisionFormat()willtellyouwhatthesystemsupports. Ifhighpfloatisavailable,GL_FRAGMENT_PRECISION_HIGHwillbedefinedas1. Agoodpatternfor"alwaysgivemethehighestprecision": #ifdefGL_FRAGMENT_PRECISION_HIGH precisionhighpfloat; #else precisionmediumpfloat; #endif ESSL100minimumrequirements(WebGL1) float think range minabovezero precision highp float24* (-2^62,2^62) 2^-62 2^-16relative mediump IEEEfloat16 (-2^14,2^14) 2^-14 2^-10relative lowp 10-bitsignedfixed (-2,2) 2^-8 2^-8absolute int think range highp int17 (-2^16,2^16) mediump int11 (-2^10,2^10) lowp int9 (-2^8,2^8) *float24:signbit,7-bitforexponent,16-bitformantissaESSL300minimumrequirements(WebGL2) float think range minabovezero precision highp IEEEfloat32 (-2^126,2^127) 2^-126 2^-24relative mediump IEEEfloat16 (-2^14,2^14) 2^-14 2^-10relative lowp 10-bitsignedfixed (-2,2) 2^-8 2^-8absolute (u)int think intrange unsignedintrange highp (u)int32 [-2^31,2^31] [0,2^32] mediump (u)int16 [-2^15,2^15] [0,2^16] lowp (u)int9 [-2^8,2^8] [0,2^9] PreferbuiltinsinsteadofbuildingyourownPreferbuiltinslikedot,mix,andnormalize.Atbest,customimplementationsmightrunasfastasthebuiltinstheyreplace,butdon'texpectthemto.Hardwareoftenhashyper-optimizedorevenspecializedinstructionsforbuiltins,andthecompilercan'treliablyreplaceyourcustombuiltin-replacementswiththespecialbuiltincodepaths.Usemipmapsforanytextureyou'llseein3dWhenindoubt,callgenerateMipmaps()aftertextureuploads.Mipmapsarecheaponmemory(only30%overhead)whileprovidingoften-largeperformanceadvantageswhentexturesare"zoomedout"orgenerallydownscaledinthedistancein3d,orevenforcube-maps! It'squickertosamplefromsmallertextureimagesduetobetterinherenttexturefetchcachelocality:Zoomingoutonanon-mipmappedtextureruinstexturefetchcachelocality,becauseneighboringpixelsnolongersamplefromneighboringtexels! However,for2dresourcesthatarenever"zoomedout",don'tpaythe30%memorysurchargeformipmaps: consttex=gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D,tex); gl.texParameterf(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR);//DefaultstoNEAREST_MIPMAP_LINEAR,formipmapping! (InWebGL2,youshouldjustusetexStoragewithlevels=1) Onecaveat:generateMipmapsonlyworksifyouwouldbeabletorenderintothetextureifyouattachedittoaframebuffer.(Thespeccallsthis"color-renderableformats")Forexample,ifasystemsupportsfloat-texturesbutnotrender-to-float,generateMipmapswillfailforfloatformats.Don'tassumeyoucanrenderintofloattexturesTherearemany,manysystemsthatsupportRGBA32Ftextures,butifyouattachonetoaframebufferyou'llgetFRAMEBUFFER_INCOMPLETE_ATTACHMENTfromcheckFramebufferStatus().Itmayworkonyoursystem,butmostmobilesystemswillnotsupportit! OnWebGL1,usetheEXT_color_buffer_half_floatandWEBGL_color_buffer_floatextensionstocheckforrender-to-float-texturesupportforfloat16andfloat32respectively. OnWebGL2,EXT_color_buffer_floatchecksforrender-to-float-texturesupportforbothfloat32andfloat16.EXT_color_buffer_half_floatispresentonsystemswhichonlysupportrenderingtofloat16textures.Render-to-float32doesn'timplyfloat32-blending!Itmayworkonyoursystem,butonmanyothersitwon't.Avoiditifyoucan.CheckfortheEXT_float_blendextensiontocheckforsupport. Float16-blendingisalwayssupported.Someformats(e.g.RGB)maybeemulatedAnumberofformats(particularlythree-channelformats)areemulated.Forexample,RGB32FisoftenactuallyRGBA32F,andLuminance8mayactuallybeRGBA8.RGB8inparticularisoftensurprisinglyslow,asmaskingoutthealphachanneland/orpatchingblendfunctionshasfairlyhighoverhead.PrefertouseRGBA8andignorethealphayourselfforbetterperformance.Avoidalpha:false,whichcanbeexpensiveSpecifyingalpha:falseduringcontextcreationcausesthebrowsertocompositetheWebGL-renderedcanvasasthoughitwereopaque,ignoringanyalphavaluestheapplicationwritesinitsfragmentshader.Onsomeplatforms,thiscapabilityunfortunatelycomesatasignificantperformancecost.TheRGBbackbuffermayhavetobeemulatedontopofanRGBAsurface,andtherearerelativelyfewtechniquesavailableintheOpenGLAPIformakingitappeartotheapplicationthatanRGBAsurfacehasnoalphachannel.Ithasbeenfoundthatallofthesetechniqueshaveapproximatelyequalperformanceimpactonaffectedplatforms. Mostapplications,eventhoserequiringalphablending,canbestructuredtoproduce1.0forthealphachannel.Theprimaryexceptionisanyapplicationrequiringdestinationalphaintheblendingfunction.Iffeasible,itisrecommendedtodothisratherthanusingalpha:false.ConsidercompressedtextureformatsWhileJPGandPNGaregenerallysmallerover-the-wire,GPUcompressedtextureformatsaresmalleroninGPUmemory,andarefastertosamplefrom.(Thisreducestexturememorybandwidth,whichispreciousonmobile)However,compressedtextureformatshaveworsequalitythanJPG,andaregenerallyonlyacceptableforcolors(note.g.normalsorcoordinates). Unfortunately,there'snosingleuniversallysupportedformat.Everysystemhasatleastoneofthefollowingthough: WEBGL_compressed_texture_s3tc(desktop) WEBGL_compressed_texture_etc1(Android) WEBGL_compressed_texture_pvrtc(iOS) WebGL2hasuniversalsupportbycombining: WEBGL_compressed_texture_s3tc(desktop) WEBGL_compressed_texture_etc(mobile) WEBGL_compressed_texture_astchasbothhigherqualityand/orhighercompression,butisonlysupportedonnewerhardware.BasisUniversaltexturecompressionformat/libraryBasisUniversalsolvesseveraloftheissuesmentionedabove.Itoffersawaytosupportallcommoncompressedtextureformatswithasinglecompressedtexturefile,throughaJavaScriptlibrarythatefficientlyconvertsformatsatloadtime.ItalsoaddsadditionalcompressionthatmakesBasisUniversalcompressedtexturefilesmuchsmallerthanregularcompressedtexturesover-the-wire,morecomparabletoJPEG. https://github.com/BinomialLLC/basis_universal/blob/master/webgl/README.mdMemoryusageofdepthandstencilformatsDepthandstencilattachmentsandformatsareactuallyinseparableonmanydevices.YoumayaskforDEPTH_COMPONENT24orSTENCIL_INDEX8,butyou'reoftengettingD24X8andX24S832bppformatsbehindthescenes.Assumethatthememoryusageofdepthandstencilformatsisroundeduptothenearestfourbytes.texImage/texSubImageuploads(esp.videos)cancausepipelineflushesMosttextureuploadsfromDOMelementswillincuraprocessingpassthatwilltemporarilyswitchGLProgramsinternally,causingapipelineflush.(PipelinesareformalizedexplicitlyinVulkan[1]etal,butareimplicitbehind-the-scenesinOpenGLandWebGL.Pipelinesaremoreorlessthetupleofshaderprogram,depth/stencil/multisample/blend/rasterizationstate) InWebGL: ... useProgram(prog1) bindFramebuffer(target) drawArrays() bindTexture(webgl_texture) texImage2D(HTMLVideoElement) drawArrays() ... Behindthescenesinthebrowser: ... useProgram(prog1) bindFramebuffer(target) drawArrays() bindTexture(webgl_texture) -texImage2D(HTMLVideoElement): +useProgram(_internal_tex_tranform_prog) +bindFramebuffer(webgl_texture._internal_framebuffer) +bindTexture(HTMLVideoElement._internal_video_tex) +drawArrays()//y-flip/colorspace-transform/alpha-(un)premultiply +bindTexture(webgl_texture) +bindFramebuffer(target) +useProgram(prog1) drawArrays() ... Preferdoinguploadsbeforestartingdrawing,oratleastbetweenpipelines: InWebGL: ... bindTexture(webgl_texture) texImage2D(HTMLVideoElement) useProgram(prog1) bindFramebuffer(target) drawArrays() bindTexture(webgl_texture) drawArrays() ... Behindthescenesinthebrowser: ... bindTexture(webgl_texture) -texImage2D(HTMLVideoElement): +useProgram(_internal_tex_tranform_prog) +bindFramebuffer(webgl_texture._internal_framebuffer) +bindTexture(HTMLVideoElement._internal_video_tex) +drawArrays()//y-flip/colorspace-transform/alpha-(un)premultiply +bindTexture(webgl_texture) +bindFramebuffer(target) useProgram(prog1) bindFramebuffer(target) drawArrays() bindTexture(webgl_texture) drawArrays() ... UsetexStoragetocreatetexturesTheWebGL2.0texImage*APIletsyoudefineeachmiplevelindependentlyandatanysize,eventhemis-matchingmipssizesarenotanerroruntildrawtimewhichmeansthereisnowaythedrivercanactuallypreparethetextureinGPUmemoryuntilthefirsttimethetextureisdrawn. Further,somedriversmightunconditionallyallocatethewholemip-chain(+30%memory!)evenifyouonlywantasinglelevel. So,prefertexStorage+texSubImagefortexturesinWebGL2UseinvalidateFramebufferStoringdatathatyouwon'tuseagaincanhavehighcost,particularlyontiled-renderingGPUscommononmobile.Whenyou'redonewiththecontentsofaframebufferattachment,useWebGL2.0'sinvalidateFramebuffertodiscardthedata,insteadofleavingthedrivertowastetimestoringthedataforlateruse.DEPTH/STENCILand/ormultisampledattachmentsinparticulararegreatcandidatesforinvalidateFramebuffer.Usenon-blockingasyncdatareadbackOperationslikereadPixelsandgetBufferSubDataaretypicallysynchronous,butusingthesameAPIs,non-blocking,asynchronousdatareadbackcanbeachieved.TheapproachinWebGL2isanalogoustotheapproachinOpenGL:https://jdashg.github.io/misc/async-gpu-downloads.html functionclientWaitAsync(gl,sync,flags,interval_ms){ returnnewPromise((resolve,reject)=>{ functiontest(){ constres=gl.clientWaitSync(sync,flags,0); if(res==gl.WAIT_FAILED){ reject(); return; } if(res==gl.TIMEOUT_EXPIRED){ setTimeout(test,interval_ms); return; } resolve(); } test()); }); } asyncfunctiongetBufferSubDataAsync( gl,target,buffer,srcByteOffset,dstBuffer, /*optional*/dstOffset,/*optional*/length){ constsync=gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE,0); gl.flush(); awaitclientWaitAsync(gl,sync,0,10); gl.deleteSync(sync); gl.bindBuffer(target,buffer); gl.getBufferSubData(target,srcByteOffset,dstBuffer,dstOffset,length); gl.bindBuffer(target,null); returndest; } asyncfunctionreadPixelsAsync(gl,x,y,w,h,format,type,dest){ constbuf=gl.createBuffer(); gl.bindBuffer(gl.PIXEL_PACK_BUFFER,buf); gl.bufferData(gl.PIXEL_PACK_BUFFER,dest.byteLength,gl.STREAM_READ); gl.readPixels(x,y,w,h,format,type,0); gl.bindBuffer(gl.PIXEL_PACK_BUFFER,null); awaitgetBufferSubDataAsync(gl,gl.PIXEL_PACK_BUFFER,buf,0,dest); gl.deleteBuffer(buf); returndest; } devicePixelRatioandhigh-dpirenderingHandlingdevicePixelRatio!=1.0istricky.Whilethecommonapproachistosetcanvas.width=width*devicePixelRatio,thiswillcausemoireartifactswithnon-integervaluesofdevicePixelRatio,asiscommonwithUIscalingonWindows,aswellaszoomingonallplatforms. Instead,wecanusenon-integervaluesforCSS'stop/bottom/left/righttofairlyreliably'pre-snap'ourcanvastowholeintegerdevicecoordinates. Demo:https://jdashg.github.io/misc/webgl/device-pixel-presnap.htmlResizeObserverand'device-pixel-content-box'Onsupportingbrowsers(Chromium?),ResizeObservercanbeusedwith'device-pixel-content-box'torequestacallbackthatincludesthetruedevicepixelsizeofanelement.Thiscanbeusedtobuildanasync-but-accuratefunction: window.getDevicePixelSize=window.getDevicePixelSize||asyncfunction(elem){ awaitnewPromise(fn_resolve=>{ constobserver=newResizeObserver(entries=>{ for(constcurofentries){ constdev_size=cur.devicePixelContentBoxSize; constret={ width:dev_size[0].inlineSize, height:dev_size[0].blockSize, }; fn_resolve(ret); observer.disconnect(); return; } throw'device-pixel-content-boxnotobservedforelem'+elem; }); observer.observe(elem,{box:'device-pixel-content-box'}); }); }; Pleaserefertothespecificationformoredetails.ImageBitmapcreationUsingtheImageBitmapOptionsdictionaryisessentialforproperlypreparingtexturesforuploadtoWebGL,butunfortunatelythere'snoobviouswaytoqueryexactlywhichdictionarymembersaresupportedbyagivenbrowser. ThisJSFiddleillustrateshowtodeterminewhichdictionarymembersagivenbrowsersupports.Foundaproblemwiththispage?EditonGitHubSourceonGitHubReportaproblemwiththiscontentonGitHubWanttofixtheproblemyourself?SeeourContributionguide.Lastmodified:May12,2022,byMDNcontributors



請為這篇文章評分?