| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005 |
- /*==============================================================================================================
- * Copyright (c) 2020 John Jackson
- * File: gs_graphics_impl.h
- * Github: https://github.com/MrFrenik/gunslinger
- * All Rights Reserved
- * MIT License
- * May all those that this source may reach be blessed by the LORD and find peace and joy in life.
- * Everyone who drinks of this water will be thirsty again; but whoever drinks of the water
- * that I will give him shall never thirst; John 4:13-14
- * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
- * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
- * The above copyright, blessing, biblical verse, notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
- * TO THE WARRANTIES OF MECHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
-
- =================================================================================================================*/
- #ifndef GS_GRAPHICS_IMPL_H
- #define GS_GRAPHICS_IMPL_H
- #ifndef GS_GRAPHICS_IMPL_CUSTOM
- #define GS_GRAPHICS_IMPL_DEFAULT
- #endif
- #ifdef GS_GRAPHICS_IMPL_DEFAULT
- // Default stuff here, if any...
- /* Graphics Info Object Query */
- gs_graphics_info_t* gs_graphics_info()
- {
- return &gs_subsystem(graphics)->info;
- }
- #endif
- #if (defined GS_GRAPHICS_IMPL_OPENGL_CORE || defined GS_GRAPHICS_IMPL_OPENGL_ES)
- #ifdef GS_GRAPHICS_IMPL_OPENGL_CORE
- #define CHECK_GL_CORE(...) __VA_ARGS__
- #else
- #define CHECK_GL_CORE(...) gs_empty_instruction(void)
- #endif
- typedef enum gsgl_uniform_type
- {
- GSGL_UNIFORMTYPE_FLOAT,
- GSGL_UNIFORMTYPE_INT,
- GSGL_UNIFORMTYPE_VEC2,
- GSGL_UNIFORMTYPE_VEC3,
- GSGL_UNIFORMTYPE_VEC4,
- GSGL_UNIFORMTYPE_MAT4,
- GSGL_UNIFORMTYPE_SAMPLER2D,
- GSGL_UNIFORMTYPE_SAMPLERCUBE
- } gsgl_uniform_type;
- /* Uniform (stores samplers as well as primitive uniforms) */
- typedef struct gsgl_uniform_t {
- char name[64]; // Name of uniform to find location
- gsgl_uniform_type type; // Type of uniform data
- uint32_t location; // Location of uniform
- size_t size; // Total data size of uniform
- uint32_t sid; // Shader id (should probably inverse this, but I don't want to force a map lookup)
- uint32_t count; // Count (used for arrays)
- } gsgl_uniform_t;
- // When a user passes in a uniform layout, that handle could then pass to a WHOLE list of uniforms (if describing a struct)
- typedef struct gsgl_uniform_list_t {
- gs_dyn_array(gsgl_uniform_t) uniforms; // Individual uniforms in list
- size_t size; // Total size of uniform data
- char name[64]; // Base name of uniform
- } gsgl_uniform_list_t;
- typedef struct gsgl_uniform_buffer_t {
- char name[64];
- uint32_t location;
- size_t size;
- uint32_t ubo;
- uint32_t sid;
- } gsgl_uniform_buffer_t;
- typedef struct gsgl_storage_buffer_t {
- char name[64];
- uint32_t buffer;
- int32_t access;
- size_t size;
- uint32_t block_idx;
- uint32_t location;
- void* map;
- GLsync sync; // Not sure about this being here...
- } gsgl_storage_buffer_t;
- /* Pipeline */
- typedef struct gsgl_pipeline_t {
- gs_graphics_blend_state_desc_t blend;
- gs_graphics_depth_state_desc_t depth;
- gs_graphics_raster_state_desc_t raster;
- gs_graphics_stencil_state_desc_t stencil;
- gs_graphics_compute_state_desc_t compute;
- gs_dyn_array(gs_graphics_vertex_attribute_desc_t) layout;
- } gsgl_pipeline_t;
- /* Render Pass */
- typedef struct gsgl_renderpass_t {
- gs_handle(gs_graphics_framebuffer_t) fbo;
- gs_dyn_array(gs_handle(gs_graphics_texture_t)) color;
- gs_handle(gs_graphics_texture_t) depth;
- gs_handle(gs_graphics_texture_t) stencil;
- } gsgl_renderpass_t;
- /* Shader */
- typedef uint32_t gsgl_shader_t;
- /* Gfx Buffer */
- typedef uint32_t gsgl_buffer_t;
- /* Texture */
- typedef struct gsgl_texture_t {
- uint32_t id;
- gs_graphics_texture_desc_t desc;
- } gsgl_texture_t;
- typedef struct gsgl_vertex_buffer_decl_t {
- gsgl_buffer_t vbo;
- gs_graphics_vertex_data_type data_type;
- size_t offset;
- } gsgl_vertex_buffer_decl_t;
- /* Cached data between draws */
- typedef struct gsgl_data_cache_t
- {
- gsgl_buffer_t vao;
- gsgl_buffer_t ibo;
- size_t ibo_elem_sz;
- gs_dyn_array(gsgl_vertex_buffer_decl_t) vdecls;
- gs_handle(gs_graphics_pipeline_t) pipeline;
- } gsgl_data_cache_t;
- /* Internal Opengl Data */
- typedef struct gsgl_data_t
- {
- gs_slot_array(gsgl_shader_t) shaders;
- gs_slot_array(gsgl_texture_t) textures;
- gs_slot_array(gsgl_buffer_t) vertex_buffers;
- gs_slot_array(gsgl_uniform_buffer_t) uniform_buffers;
- gs_slot_array(gsgl_storage_buffer_t) storage_buffers;
- gs_slot_array(gsgl_buffer_t) index_buffers;
- gs_slot_array(gsgl_buffer_t) frame_buffers;
- gs_slot_array(gsgl_uniform_list_t) uniforms;
- gs_slot_array(gsgl_pipeline_t) pipelines;
- gs_slot_array(gsgl_renderpass_t) renderpasses;
- // All the required uniform data for strict aliasing.
- struct {
- gs_dyn_array(uint32_t) ui32;
- gs_dyn_array(int32_t) i32;
- gs_dyn_array(float) flt;
- gs_dyn_array(gs_vec2) vec2;
- gs_dyn_array(gs_vec3) vec3;
- gs_dyn_array(gs_vec4) vec4;
- gs_dyn_array(gs_mat4) mat4;
- } uniform_data;
- // Cached data between draw calls (to minimize state changes)
- gsgl_data_cache_t cache;
- } gsgl_data_t;
- /* Internal OGL Command Buffer Op Code */
- typedef enum gs_opengl_op_code_type
- {
- GS_OPENGL_OP_BEGIN_RENDER_PASS = 0x00,
- GS_OPENGL_OP_END_RENDER_PASS,
- GS_OPENGL_OP_SET_VIEWPORT,
- GS_OPENGL_OP_SET_VIEW_SCISSOR,
- GS_OPENGL_OP_CLEAR,
- GS_OPENGL_OP_REQUEST_BUFFER_UPDATE,
- GS_OPENGL_OP_REQUEST_TEXTURE_UPDATE,
- GS_OPENGL_OP_BIND_PIPELINE,
- GS_OPENGL_OP_APPLY_BINDINGS,
- GS_OPENGL_OP_DISPATCH_COMPUTE,
- GS_OPENGL_OP_DRAW,
- } gs_opengl_op_code_type;
- void gsgl_reset_data_cache(gsgl_data_cache_t* cache)
- {
- cache->ibo = 0;
- cache->ibo_elem_sz = 0;
- cache->pipeline = gs_handle_invalid(gs_graphics_pipeline_t);
- gs_dyn_array_clear(cache->vdecls);
- }
- void gsgl_pipeline_state()
- {
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- glBindTexture(GL_TEXTURE_2D, 0);
- glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
- CHECK_GL_CORE(
- glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0);
- )
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_STENCIL_TEST);
- glDisable(GL_BLEND);
- CHECK_GL_CORE(
- glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
- );
- glDisable(GL_MULTISAMPLE);
- CHECK_GL_CORE(
- gs_graphics_info_t* info = gs_graphics_info();
- if (info->compute.available) {
- glBindImageTexture(0, 0, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
- }
- )
- }
- void GLAPIENTRY
- gsgl_message_cb(uint32_t source, uint32_t type, uint32_t id, uint32_t severity, int32_t length,
- const GLchar* message, void* user_param)
- {
- return;
- if (type == GL_DEBUG_TYPE_ERROR) {
- gs_println("GL [DEBUG]: %s type = 0x%x, severity = 0x%x, message = %s",
- type == GL_DEBUG_TYPE_ERROR ? "GL ERROR" : "", type, severity, message);
- }
- }
- /* GS/OGL Utilities */
- int32_t gsgl_buffer_usage_to_gl_enum(gs_graphics_buffer_usage_type type)
- {
- int32_t mode = GL_STATIC_DRAW;
- switch (type) {
- default:
- case GS_GRAPHICS_BUFFER_USAGE_STATIC: mode = GL_STATIC_DRAW; break;
- case GS_GRAPHICS_BUFFER_USAGE_STREAM: mode = GL_STREAM_DRAW; break;
- case GS_GRAPHICS_BUFFER_USAGE_DYNAMIC: mode = GL_DYNAMIC_DRAW; break;
- }
- return mode;
- }
- uint32_t gsgl_access_type_to_gl_access_type(gs_graphics_access_type type)
- {
- CHECK_GL_CORE(
- uint32_t access = GL_WRITE_ONLY;
- switch (type)
- {
- case GS_GRAPHICS_ACCESS_WRITE_ONLY: access = GL_WRITE_ONLY; break;
- case GS_GRAPHICS_ACCESS_READ_ONLY: access = GL_READ_ONLY; break;
- case GS_GRAPHICS_ACCESS_READ_WRITE: access = GL_READ_WRITE; break;
- default: break;
- }
- return access;
- )
- return 0;
- }
- uint32_t gsgl_texture_wrap_to_gl_texture_wrap(gs_graphics_texture_wrapping_type type)
- {
- uint32_t wrap = GL_REPEAT;
- switch (type) {
- default:
- case GS_GRAPHICS_TEXTURE_WRAP_REPEAT: wrap = GL_REPEAT; break;
- case GS_GRAPHICS_TEXTURE_WRAP_MIRRORED_REPEAT: wrap = GL_MIRRORED_REPEAT; break;
- case GS_GRAPHICS_TEXTURE_WRAP_CLAMP_TO_EDGE: wrap = GL_CLAMP_TO_EDGE; break;
- CHECK_GL_CORE(case GS_GRAPHICS_TEXTURE_WRAP_CLAMP_TO_BORDER: wrap = GL_CLAMP_TO_BORDER; break;)
- };
- return wrap;
- }
- uint32_t gsgl_texture_format_to_gl_data_type(gs_graphics_texture_format_type type)
- {
- uint32_t format = GL_UNSIGNED_BYTE;
- switch (type) {
- default:
- case GS_GRAPHICS_TEXTURE_FORMAT_A8: format = GL_UNSIGNED_BYTE; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_R8: format = GL_UNSIGNED_BYTE; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_RGB8: format = GL_UNSIGNED_BYTE; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_R32UI: format = GL_UNSIGNED_INT; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_R16UI: format = GL_UNSIGNED_SHORT; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_RGBA8: format = GL_UNSIGNED_BYTE; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_RGBA16F: format = GL_FLOAT; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_RGBA32F: format = GL_FLOAT; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_R32F: format = GL_FLOAT; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH8: format = GL_FLOAT; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH16: format = GL_FLOAT; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH24: format = GL_FLOAT; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH32F: format = GL_FLOAT; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH24_STENCIL8: format = GL_UNSIGNED_INT_24_8; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH32F_STENCIL8: format = GL_FLOAT_32_UNSIGNED_INT_24_8_REV; break;
- }
- return format;
- }
- uint32_t gsgl_texture_format_to_gl_texture_format(gs_graphics_texture_format_type type)
- {
- uint32_t dt = GL_RGBA;
- switch (type)
- {
- default:
- case GS_GRAPHICS_TEXTURE_FORMAT_RGBA8: dt = GL_RGBA; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_A8: dt = GL_ALPHA; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_R8: dt = GL_RED; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_R16UI: dt = GL_RED_INTEGER; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_R32UI: dt = GL_RED_INTEGER; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_R32F: dt = GL_RED; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_RGB8: dt = GL_RGB; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_RGBA16F: dt = GL_RGBA; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_RGBA32F: dt = GL_RGBA; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH8: dt = GL_DEPTH_COMPONENT; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH16: dt = GL_DEPTH_COMPONENT; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH24: dt = GL_DEPTH_COMPONENT; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH32F: dt = GL_DEPTH_COMPONENT; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH24_STENCIL8: dt = GL_DEPTH_STENCIL;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH32F_STENCIL8: dt = GL_DEPTH_STENCIL; break;
- }
- return dt;
- }
- uint32_t gsgl_texture_format_to_gl_texture_internal_format(gs_graphics_texture_format_type type)
- {
- uint32_t format = GL_UNSIGNED_BYTE;
- switch (type) {
- case GS_GRAPHICS_TEXTURE_FORMAT_A8: format = GL_ALPHA; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_R8: format = GL_RED; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_R32UI: format = GL_R32UI; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_R16UI: format = GL_R16UI; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_R32F: format = GL_R32F; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_RGB8: format = GL_RGB8; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_RGBA8: format = GL_RGBA8; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_RGBA16F: format = GL_RGBA16F; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_RGBA32F: format = GL_RGBA32F; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH8: format = GL_DEPTH_COMPONENT; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH16: format = GL_DEPTH_COMPONENT16; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH24: format = GL_DEPTH_COMPONENT24; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH32F: format = GL_DEPTH_COMPONENT32F; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH24_STENCIL8: format = GL_DEPTH24_STENCIL8; break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH32F_STENCIL8: format = GL_DEPTH32F_STENCIL8; break;
- }
- return format;
- }
- uint32_t gsgl_shader_stage_to_gl_stage(gs_graphics_shader_stage_type type)
- {
- uint32_t stage = GL_VERTEX_SHADER;
- switch (type) {
- default:
- case GS_GRAPHICS_SHADER_STAGE_VERTEX: stage = GL_VERTEX_SHADER; break;
- case GS_GRAPHICS_SHADER_STAGE_FRAGMENT: stage = GL_FRAGMENT_SHADER; break;
- CHECK_GL_CORE(case GS_GRAPHICS_SHADER_STAGE_COMPUTE: stage = GL_COMPUTE_SHADER; break;)
- }
- return stage;
- }
- uint32_t gsgl_primitive_to_gl_primitive(gs_graphics_primitive_type type)
- {
- uint32_t prim = GL_TRIANGLES;
- switch (type) {
- default:
- case GS_GRAPHICS_PRIMITIVE_TRIANGLES: prim = GL_TRIANGLES; break;
- case GS_GRAPHICS_PRIMITIVE_LINES: prim = GL_LINES; break;
- CHECK_GL_CORE(case GS_GRAPHICS_PRIMITIVE_QUADS: prim = GL_QUADS; break;)
- }
- return prim;
- }
- uint32_t gsgl_blend_equation_to_gl_blend_eq(gs_graphics_blend_equation_type eq)
- {
- uint32_t beq = GL_FUNC_ADD;
- switch (eq) {
- default:
- case GS_GRAPHICS_BLEND_EQUATION_ADD: beq = GL_FUNC_ADD; break;
- case GS_GRAPHICS_BLEND_EQUATION_SUBTRACT: beq = GL_FUNC_SUBTRACT; break;
- case GS_GRAPHICS_BLEND_EQUATION_REVERSE_SUBTRACT: beq = GL_FUNC_REVERSE_SUBTRACT; break;
- case GS_GRAPHICS_BLEND_EQUATION_MIN: beq = GL_MIN; break;
- case GS_GRAPHICS_BLEND_EQUATION_MAX: beq = GL_MAX; break;
- };
- return beq;
- }
- uint32_t gsgl_blend_mode_to_gl_blend_mode(gs_graphics_blend_mode_type type, uint32_t def)
- {
- uint32_t mode = def;
- switch (type) {
- case GS_GRAPHICS_BLEND_MODE_ZERO: mode = GL_ZERO; break;
- case GS_GRAPHICS_BLEND_MODE_ONE: mode = GL_ONE; break;
- case GS_GRAPHICS_BLEND_MODE_SRC_COLOR: mode = GL_SRC_COLOR; break;
- case GS_GRAPHICS_BLEND_MODE_ONE_MINUS_SRC_COLOR: mode = GL_ONE_MINUS_SRC_COLOR; break;
- case GS_GRAPHICS_BLEND_MODE_DST_COLOR: mode = GL_DST_COLOR; break;
- case GS_GRAPHICS_BLEND_MODE_ONE_MINUS_DST_COLOR: mode = GL_ONE_MINUS_DST_COLOR; break;
- case GS_GRAPHICS_BLEND_MODE_SRC_ALPHA: mode = GL_SRC_ALPHA; break;
- case GS_GRAPHICS_BLEND_MODE_ONE_MINUS_SRC_ALPHA: mode = GL_ONE_MINUS_SRC_ALPHA; break;
- case GS_GRAPHICS_BLEND_MODE_DST_ALPHA: mode = GL_DST_ALPHA; break;
- case GS_GRAPHICS_BLEND_MODE_ONE_MINUS_DST_ALPHA: mode = GL_ONE_MINUS_DST_ALPHA; break;
- case GS_GRAPHICS_BLEND_MODE_CONSTANT_COLOR: mode = GL_CONSTANT_COLOR; break;
- case GS_GRAPHICS_BLEND_MODE_ONE_MINUS_CONSTANT_COLOR: mode = GL_ONE_MINUS_CONSTANT_COLOR; break;
- case GS_GRAPHICS_BLEND_MODE_CONSTANT_ALPHA: mode = GL_CONSTANT_ALPHA; break;
- case GS_GRAPHICS_BLEND_MODE_ONE_MINUS_CONSTANT_ALPHA: mode = GL_ONE_MINUS_CONSTANT_ALPHA; break;
- }
- return mode;
- }
- uint32_t gsgl_cull_face_to_gl_cull_face(gs_graphics_face_culling_type type)
- {
- uint32_t fc = GL_BACK;
- switch (type) {
- default:
- case GS_GRAPHICS_FACE_CULLING_BACK: fc = GL_BACK; break;
- case GS_GRAPHICS_FACE_CULLING_FRONT: fc = GL_FRONT; break;
- case GS_GRAPHICS_FACE_CULLING_FRONT_AND_BACK: fc = GL_FRONT_AND_BACK; break;
- }
- return fc;
- }
- uint32_t gsgl_winding_order_to_gl_winding_order(gs_graphics_winding_order_type type)
- {
- uint32_t wo = GL_CCW;
- switch (type)
- {
- case GS_GRAPHICS_WINDING_ORDER_CCW: wo = GL_CCW; break;
- case GS_GRAPHICS_WINDING_ORDER_CW: wo = GL_CW; break;
- }
- return wo;
- }
- uint32_t gsgl_depth_func_to_gl_depth_func(gs_graphics_depth_func_type type)
- {
- uint32_t func = GL_LESS;
- switch (type) {
- default:
- case GS_GRAPHICS_DEPTH_FUNC_LESS: func = GL_LESS; break;
- case GS_GRAPHICS_DEPTH_FUNC_NEVER: func = GL_NEVER; break;
- case GS_GRAPHICS_DEPTH_FUNC_EQUAL: func = GL_EQUAL; break;
- case GS_GRAPHICS_DEPTH_FUNC_LEQUAL: func = GL_LEQUAL; break;
- case GS_GRAPHICS_DEPTH_FUNC_GREATER: func = GL_GREATER; break;
- case GS_GRAPHICS_DEPTH_FUNC_NOTEQUAL: func = GL_NOTEQUAL; break;
- case GS_GRAPHICS_DEPTH_FUNC_GEQUAL: func = GL_GEQUAL; break;
- case GS_GRAPHICS_DEPTH_FUNC_ALWAYS: func = GL_ALWAYS; break;
- }
- return func;
- }
- bool gsgl_depth_mask_to_gl_mask(gs_graphics_depth_mask_type type)
- {
- bool ret = true;
- switch (type) {
- default:
- case GS_GRAPHICS_DEPTH_MASK_ENABLED: ret = true; break;
- case GS_GRAPHICS_DEPTH_MASK_DISABLED: ret = false; break;
- }
- return ret;
- }
- uint32_t gsgl_stencil_func_to_gl_stencil_func(gs_graphics_stencil_func_type type)
- {
- uint32_t func = GL_ALWAYS;
- switch (type) {
- default:
- case GS_GRAPHICS_STENCIL_FUNC_LESS: func = GL_LESS; break;
- case GS_GRAPHICS_STENCIL_FUNC_NEVER: func = GL_NEVER; break;
- case GS_GRAPHICS_STENCIL_FUNC_EQUAL: func = GL_EQUAL; break;
- case GS_GRAPHICS_STENCIL_FUNC_LEQUAL: func = GL_LEQUAL; break;
- case GS_GRAPHICS_STENCIL_FUNC_GREATER: func = GL_GREATER; break;
- case GS_GRAPHICS_STENCIL_FUNC_NOTEQUAL: func = GL_NOTEQUAL; break;
- case GS_GRAPHICS_STENCIL_FUNC_GEQUAL: func = GL_GEQUAL; break;
- case GS_GRAPHICS_STENCIL_FUNC_ALWAYS: func = GL_ALWAYS; break;
- }
- return func;
- }
- uint32_t gsgl_stencil_op_to_gl_stencil_op(gs_graphics_stencil_op_type type)
- {
- uint32_t op = GL_KEEP;
- switch (type) {
- default:
- case GS_GRAPHICS_STENCIL_OP_KEEP: op = GL_KEEP; break;
- case GS_GRAPHICS_STENCIL_OP_ZERO: op = GL_ZERO; break;
- case GS_GRAPHICS_STENCIL_OP_REPLACE: op = GL_REPLACE; break;
- case GS_GRAPHICS_STENCIL_OP_INCR: op = GL_INCR; break;
- case GS_GRAPHICS_STENCIL_OP_INCR_WRAP: op = GL_INCR_WRAP; break;
- case GS_GRAPHICS_STENCIL_OP_DECR: op = GL_DECR; break;
- case GS_GRAPHICS_STENCIL_OP_DECR_WRAP: op = GL_DECR_WRAP; break;
- case GS_GRAPHICS_STENCIL_OP_INVERT: op = GL_INVERT; break;
- }
- return op;
- }
- gsgl_uniform_type gsgl_uniform_type_to_gl_uniform_type(gs_graphics_uniform_type gstype)
- {
- gsgl_uniform_type type = GSGL_UNIFORMTYPE_FLOAT;
- switch (gstype) {
- default:
- case GS_GRAPHICS_UNIFORM_FLOAT: type = GSGL_UNIFORMTYPE_FLOAT; break;
- case GS_GRAPHICS_UNIFORM_INT: type = GSGL_UNIFORMTYPE_INT; break;
- case GS_GRAPHICS_UNIFORM_VEC2: type = GSGL_UNIFORMTYPE_VEC2; break;
- case GS_GRAPHICS_UNIFORM_VEC3: type = GSGL_UNIFORMTYPE_VEC3; break;
- case GS_GRAPHICS_UNIFORM_VEC4: type = GSGL_UNIFORMTYPE_VEC4; break;
- case GS_GRAPHICS_UNIFORM_MAT4: type = GSGL_UNIFORMTYPE_MAT4; break;
- case GS_GRAPHICS_UNIFORM_USAMPLER2D: type = GSGL_UNIFORMTYPE_SAMPLER2D; break;
- case GS_GRAPHICS_UNIFORM_SAMPLER2D: type = GSGL_UNIFORMTYPE_SAMPLER2D; break;
- case GS_GRAPHICS_UNIFORM_SAMPLERCUBE: type = GSGL_UNIFORMTYPE_SAMPLERCUBE; break;
- }
- return type;
- }
- uint32_t gsgl_index_buffer_size_to_gl_index_type(size_t sz)
- {
- uint32_t type = GL_UNSIGNED_INT;
- switch (sz) {
- default:
- case 4: type = GL_UNSIGNED_INT; break;
- case 2: type = GL_UNSIGNED_SHORT; break;
- case 1: type = GL_UNSIGNED_BYTE; break;
- }
- return type;
- }
- size_t gsgl_get_byte_size_of_vertex_attribute(gs_graphics_vertex_attribute_type type)
- {
- size_t byte_size = 0;
- switch (type) {
- case GS_GRAPHICS_VERTEX_ATTRIBUTE_FLOAT4: { byte_size = sizeof(float32_t) * 4; } break;
- case GS_GRAPHICS_VERTEX_ATTRIBUTE_FLOAT3: { byte_size = sizeof(float32_t) * 3; } break;
- case GS_GRAPHICS_VERTEX_ATTRIBUTE_FLOAT2: { byte_size = sizeof(float32_t) * 2; } break;
- case GS_GRAPHICS_VERTEX_ATTRIBUTE_FLOAT: { byte_size = sizeof(float32_t) * 1; } break;
- case GS_GRAPHICS_VERTEX_ATTRIBUTE_UINT4: { byte_size = sizeof(uint32_t) * 4; } break;
- case GS_GRAPHICS_VERTEX_ATTRIBUTE_UINT3: { byte_size = sizeof(uint32_t) * 3; } break;
- case GS_GRAPHICS_VERTEX_ATTRIBUTE_UINT2: { byte_size = sizeof(uint32_t) * 2; } break;
- case GS_GRAPHICS_VERTEX_ATTRIBUTE_UINT: { byte_size = sizeof(uint32_t) * 1; } break;
- case GS_GRAPHICS_VERTEX_ATTRIBUTE_BYTE4: { byte_size = sizeof(uint8_t) * 4; } break;
- case GS_GRAPHICS_VERTEX_ATTRIBUTE_BYTE3: { byte_size = sizeof(uint8_t) * 3; } break;
- case GS_GRAPHICS_VERTEX_ATTRIBUTE_BYTE2: { byte_size = sizeof(uint8_t) * 2; } break;
- case GS_GRAPHICS_VERTEX_ATTRIBUTE_BYTE: { byte_size = sizeof(uint8_t) * 1; } break;
- }
- return byte_size;
- }
- size_t gsgl_calculate_vertex_size_in_bytes(gs_graphics_vertex_attribute_desc_t* layout, uint32_t count)
- {
- // Iterate through all formats in delcarations and calculate total size
- size_t sz = 0;
- for (uint32_t i = 0; i < count; ++i) {
- gs_graphics_vertex_attribute_type type = layout[i].format;
- sz += gsgl_get_byte_size_of_vertex_attribute(type);
- }
- return sz;
- }
- size_t gsgl_get_vertex_attr_byte_offest(gs_dyn_array(gs_graphics_vertex_attribute_desc_t) layout, uint32_t idx)
- {
- // Recursively calculate offset
- size_t total_offset = 0;
- // Base case
- if (idx == 0) {
- return total_offset;
- }
- // Calculate total offset up to this point
- for (uint32_t i = 0; i < idx; ++i) {
- total_offset += gsgl_get_byte_size_of_vertex_attribute(layout[i].format);
- }
- return total_offset;
- }
- size_t gsgl_uniform_data_size_in_bytes(gs_graphics_uniform_type type)
- {
- size_t sz = 0;
- switch (type) {
- case GS_GRAPHICS_UNIFORM_FLOAT: sz = sizeof(float); break;
- case GS_GRAPHICS_UNIFORM_INT: sz = sizeof(int32_t); break;
- case GS_GRAPHICS_UNIFORM_VEC2: sz = 2 * sizeof(float); break;
- case GS_GRAPHICS_UNIFORM_VEC3: sz = 3 * sizeof(float); break;
- case GS_GRAPHICS_UNIFORM_VEC4: sz = 4 * sizeof(float); break;
- case GS_GRAPHICS_UNIFORM_MAT4: sz = 16 * sizeof(float); break;
- case GS_GRAPHICS_UNIFORM_SAMPLER2D: sz = sizeof(gs_handle(gs_graphics_texture_t)); break; // handle size
- case GS_GRAPHICS_UNIFORM_USAMPLER2D: sz = sizeof(gs_handle(gs_graphics_texture_t)); break; // handle size
- case GS_GRAPHICS_UNIFORM_SAMPLERCUBE: sz = sizeof(gs_handle(gs_graphics_texture_t)); break; // handle size
- default: {
- sz = 0;
- } break;
- }
- return sz;
- }
- /* Graphics Interface Creation / Initialization / Shutdown / Destruction */
- GS_API_DECL gs_graphics_t*
- gs_graphics_create()
- {
- // Construct new graphics interface
- gs_graphics_t* gfx = gs_malloc_init(gs_graphics_t);
- // Construct internal data for opengl
- gfx->user_data = gs_malloc_init(gsgl_data_t);
- return gfx;
- }
- GS_API_DECL void
- gs_graphics_destroy(gs_graphics_t* graphics)
- {
- // Free all resources (assuming they've been freed from the GPU already)
- if (graphics == NULL) return;
- gsgl_data_t* ogl = (gsgl_data_t*)graphics->user_data;
- #define OGL_FREE_DATA(SA, T, FUNC)\
- do {\
- for (\
- gs_slot_array_iter it = 1;\
- gs_slot_array_iter_valid(SA, it);\
- gs_slot_array_iter_advance(SA, it)\
- )\
- {\
- gs_handle(T) hndl = gs_default_val();\
- hndl.id = it;\
- FUNC(hndl);\
- }\
- } while (0)
- // Free all gl data
- if (ogl->pipelines) OGL_FREE_DATA(ogl->pipelines, gs_graphics_pipeline_t, gs_graphics_pipeline_destroy);
- if (ogl->shaders) OGL_FREE_DATA(ogl->shaders, gs_graphics_shader_t, gs_graphics_shader_destroy);
- if (ogl->vertex_buffers) OGL_FREE_DATA(ogl->vertex_buffers, gs_graphics_vertex_buffer_t, gs_graphics_vertex_buffer_destroy);
- if (ogl->index_buffers) OGL_FREE_DATA(ogl->index_buffers, gs_graphics_index_buffer_t, gs_graphics_index_buffer_destroy);
- if (ogl->renderpasses) OGL_FREE_DATA(ogl->renderpasses, gs_graphics_renderpass_t, gs_graphics_renderpass_destroy);
- if (ogl->frame_buffers) OGL_FREE_DATA(ogl->frame_buffers, gs_graphics_framebuffer_t, gs_graphics_framebuffer_destroy);
- if (ogl->textures) OGL_FREE_DATA(ogl->textures, gs_graphics_texture_t, gs_graphics_texture_destroy);
- if (ogl->uniforms) OGL_FREE_DATA(ogl->uniforms, gs_graphics_uniform_t, gs_graphics_uniform_destroy);
- if (ogl->uniform_buffers) OGL_FREE_DATA(ogl->uniform_buffers, gs_graphics_uniform_buffer_t, gs_graphics_uniform_buffer_destroy);
- // if (ogl->storage_buffers) OGL_FREE_DATA(ogl->storage_buffers, gs_graphics_storage_buffer_t, gs_graphics_storage_buffer_destroy);
- gs_slot_array_free(ogl->shaders);
- gs_slot_array_free(ogl->vertex_buffers);
- gs_slot_array_free(ogl->index_buffers);
- gs_slot_array_free(ogl->frame_buffers);
- gs_slot_array_free(ogl->uniforms);
- gs_slot_array_free(ogl->textures);
- gs_slot_array_free(ogl->pipelines);
- gs_slot_array_free(ogl->renderpasses);
- gs_slot_array_free(ogl->uniform_buffers);
- gs_slot_array_free(ogl->storage_buffers);
- // Free uniform data array
- gs_dyn_array_free(ogl->uniform_data.mat4);
- gs_dyn_array_free(ogl->uniform_data.vec4);
- gs_dyn_array_free(ogl->uniform_data.vec3);
- gs_dyn_array_free(ogl->uniform_data.vec2);
- gs_dyn_array_free(ogl->uniform_data.flt);
- gs_dyn_array_free(ogl->uniform_data.i32);
- gs_dyn_array_free(ogl->uniform_data.ui32);
- // Free data cache
- gs_dyn_array_free(ogl->cache.vdecls);
- gs_free(graphics);
- graphics = NULL;
- }
- GS_API_DECL void
- gs_graphics_shutdown(gs_graphics_t* graphics)
- {
- }
- gsgl_texture_t gl_texture_update_internal(const gs_graphics_texture_desc_t* desc, uint32_t hndl)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- gsgl_texture_t tex = gs_default_val();
- if (hndl) tex = gs_slot_array_get(ogl->textures, hndl);
- uint32_t width = desc->width;
- uint32_t height = desc->height;
- void* data = NULL;
- if (!hndl)
- {
- glGenTextures(1, &tex.id);
- }
- GLenum target = 0x00;
- switch (desc->type)
- {
- default:
- case GS_GRAPHICS_TEXTURE_2D: {target = GL_TEXTURE_2D;} break;
- case GS_GRAPHICS_TEXTURE_CUBEMAP: {target = GL_TEXTURE_CUBE_MAP;} break;
- }
- glBindTexture(target, tex.id);
- uint32_t cnt = GS_GRAPHICS_TEXTURE_DATA_MAX;
- switch (desc->type)
- {
- case GS_GRAPHICS_TEXTURE_2D: cnt = 1; break;
- }
- for (uint32_t i = 0; i < cnt; ++i)
- {
- GLenum itarget = 0x00;
- data = desc->data[i];
- switch (desc->type)
- {
- default:
- case GS_GRAPHICS_TEXTURE_2D: {itarget = GL_TEXTURE_2D;} break;
- case GS_GRAPHICS_TEXTURE_CUBEMAP: {itarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;} break;
- }
- if (tex.desc.width * tex.desc.height < width * height)
- {
- // Construct texture based on appropriate format
- switch(desc->format)
- {
- case GS_GRAPHICS_TEXTURE_FORMAT_A8: glTexImage2D(itarget, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_R8: glTexImage2D(itarget, 0, GL_RED, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_R32UI: glTexImage2D(itarget, 0, GL_R32UI, width, height, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_R16UI: glTexImage2D(itarget, 0, GL_R16UI, width, height, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_RG8: glTexImage2D(itarget, 0, GL_RG8, width, height, 0, GL_RG, GL_UNSIGNED_BYTE, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_RGB8: glTexImage2D(itarget, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_RGBA8: glTexImage2D(itarget, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_R32F: glTexImage2D(itarget, 0, GL_R32F, width, height, 0, GL_RED, GL_FLOAT, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_RGBA16F: glTexImage2D(itarget, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_RGBA32F: glTexImage2D(itarget, 0, GL_RGBA32F, width, height, 0, GL_RGBA, GL_FLOAT, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH8: glTexImage2D(itarget, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH16: glTexImage2D(itarget, 0, GL_DEPTH_COMPONENT16, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH24: glTexImage2D(itarget, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH32F: glTexImage2D(itarget, 0, GL_DEPTH_COMPONENT32F, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH24_STENCIL8: glTexImage2D(itarget, 0, GL_DEPTH24_STENCIL8, width, height, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, data);
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH32F_STENCIL8: glTexImage2D(itarget, 0, GL_DEPTH32F_STENCIL8, width, height, 0, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, data); break;
- // NOTE(john): Because Apple is a shit company, I have to section this off and provide support for 4.1 only features.
- // case GS_GRAPHICS_TEXTURE_FORMAT_STENCIL8: glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT8, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, data); break;
- default: break;
- }
- }
- else
- {
- // Subimage
- switch (desc->format)
- {
- case GS_GRAPHICS_TEXTURE_FORMAT_A8: glTexSubImage2D(itarget, 0, (u32)desc->offset.x, (u32)desc->offset.y, width, height, GL_ALPHA, GL_UNSIGNED_BYTE, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_R8: glTexSubImage2D(itarget, 0, (u32)desc->offset.x, (u32)desc->offset.y, width, height, GL_RED, GL_UNSIGNED_BYTE, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_R32UI: glTexImage2D(itarget, 0, GL_R32UI, width, height, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_R16UI: glTexImage2D(itarget, 0, GL_R16UI, width, height, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_RG8: glTexSubImage2D(itarget, 0, (u32)desc->offset.x, (u32)desc->offset.y, width, height, GL_RG, GL_UNSIGNED_BYTE, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_RGB8: glTexSubImage2D(itarget, 0, (u32)desc->offset.x, (u32)desc->offset.y, width, height, GL_RGB, GL_UNSIGNED_BYTE, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_RGBA8: glTexSubImage2D(itarget, 0, (u32)desc->offset.x, (u32)desc->offset.y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_R32F: glTexImage2D(itarget, 0, GL_R32F, width, height, 0, GL_RED, GL_FLOAT, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_RGBA16F: glTexSubImage2D(itarget, 0, (u32)desc->offset.x, (u32)desc->offset.y, width, height, GL_RGBA, GL_FLOAT, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_RGBA32F: glTexSubImage2D(itarget, 0, (u32)desc->offset.x, (u32)desc->offset.y, width, height, GL_RGBA, GL_FLOAT, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH8: glTexSubImage2D(itarget, 0, (u32)desc->offset.x, (u32)desc->offset.y, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH16: glTexSubImage2D(itarget, 0, (u32)desc->offset.x, (u32)desc->offset.y, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH24: glTexSubImage2D(itarget, 0, (u32)desc->offset.x, (u32)desc->offset.y, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH32F: glTexSubImage2D(itarget, 0, (u32)desc->offset.x, (u32)desc->offset.y, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, data); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH24_STENCIL8: glTexSubImage2D(itarget, 0, (u32)desc->offset.x, (u32)desc->offset.y, width, height, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, data);
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH32F_STENCIL8: glTexSubImage2D(itarget, 0, (u32)desc->offset.x, (u32)desc->offset.y, width, height, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, data); break;
- // NOTE(john): Because Apple is a shit company, I have to section this off and provide support for 4.1 only features.
- // case GS_GRAPHICS_TEXTURE_FORMAT_STENCIL8: glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT8, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, data); break;
- default: break;
- }
- }
- }
- int32_t mag_filter = desc->mag_filter == GS_GRAPHICS_TEXTURE_FILTER_NEAREST ? GL_NEAREST : GL_LINEAR;
- int32_t min_filter = desc->min_filter == GS_GRAPHICS_TEXTURE_FILTER_NEAREST ? GL_NEAREST : GL_LINEAR;
- if (desc->num_mips) {
- if (desc->min_filter == GS_GRAPHICS_TEXTURE_FILTER_NEAREST) {
- min_filter = desc->mip_filter == GS_GRAPHICS_TEXTURE_FILTER_NEAREST ? GL_NEAREST_MIPMAP_NEAREST :
- GL_NEAREST_MIPMAP_LINEAR;
- }
- else {
- min_filter = desc->mip_filter == GS_GRAPHICS_TEXTURE_FILTER_NEAREST ? GL_LINEAR_MIPMAP_NEAREST :
- GL_NEAREST_MIPMAP_LINEAR;
- }
- }
- const uint32_t texture_wrap_s = gsgl_texture_wrap_to_gl_texture_wrap(desc->wrap_s);
- const uint32_t texture_wrap_t = gsgl_texture_wrap_to_gl_texture_wrap(desc->wrap_t);
- const uint32_t texture_wrap_r = gsgl_texture_wrap_to_gl_texture_wrap(desc->wrap_r);
- if (desc->num_mips) {
- glGenerateMipmap(target);
- }
- // Need to make sure this is available before being able to use
- CHECK_GL_CORE(
- float aniso = 0.0f;
- glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &aniso);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, aniso);
- );
- glTexParameteri(target, GL_TEXTURE_WRAP_S, texture_wrap_s);
- glTexParameteri(target, GL_TEXTURE_WRAP_T, texture_wrap_t);
- glTexParameteri(target, GL_TEXTURE_WRAP_R, texture_wrap_r);
- glTexParameteri(target, GL_TEXTURE_MAG_FILTER, mag_filter);
- glTexParameteri(target, GL_TEXTURE_MIN_FILTER, min_filter);
- // Unbind buffers
- glBindTexture(target, 0);
- glBindRenderbuffer(GL_RENDERBUFFER, 0);
- // Set description
- tex.desc = *desc;
- // Add texture to internal resource pool and return handle
- return tex;
- }
- /* Resource Creation */
- GS_API_DECL gs_handle(gs_graphics_texture_t)
- gs_graphics_texture_create_impl(const gs_graphics_texture_desc_t* desc)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- gsgl_texture_t tex = gl_texture_update_internal(desc, 0);
- // Add texture to internal resource pool and return handle
- return (gs_handle_create(gs_graphics_texture_t, gs_slot_array_insert(ogl->textures, tex)));
- }
- GS_API_DECL gs_handle(gs_graphics_uniform_t)
- gs_graphics_uniform_create_impl(const gs_graphics_uniform_desc_t* desc)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- // Assert if data isn't named
- if (*desc->name == 0) {
- gs_println("Warning: Uniform must be named for OpenGL.");
- return gs_handle_invalid(gs_graphics_uniform_t);
- }
- uint32_t ct = !desc->layout ? 0 : !desc->layout_size ? 1 : (uint32_t)desc->layout_size / (uint32_t)sizeof(gs_graphics_uniform_layout_desc_t);
- if (ct < 1) {
- gs_println("Warning: Uniform layout description must not be empty for: %s.", desc->name);
- return gs_handle_invalid(gs_graphics_uniform_t);
- }
- // Construct list for uniform handles
- gsgl_uniform_list_t ul = gs_default_val();
- memcpy(ul.name, desc->name, 64);
- // Iterate layout, construct individual handles
- for (uint32_t i = 0; i < ct; ++i)
- {
- // Uniform to fill out
- gsgl_uniform_t u = gs_default_val();
- // Cache layout
- gs_graphics_uniform_layout_desc_t* layout = &desc->layout[i];
- memcpy(u.name, layout->fname, 64);
- u.type = gsgl_uniform_type_to_gl_uniform_type(layout->type);
- u.size = gsgl_uniform_data_size_in_bytes(layout->type);
- u.count = layout->count ? layout->count : 1;
- u.location = UINT32_MAX;
- // Add to size of ul
- ul.size += u.size * u.count;
- // Push uniform into list
- gs_dyn_array_push(ul.uniforms, u);
- }
- return gs_handle_create(gs_graphics_uniform_t, gs_slot_array_insert(ogl->uniforms, ul));
- }
- GS_API_DECL gs_handle(gs_graphics_vertex_buffer_t)
- gs_graphics_vertex_buffer_create_impl(const gs_graphics_vertex_buffer_desc_t* desc)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- gs_handle(gs_graphics_vertex_buffer_t) hndl = gs_default_val();
- gsgl_buffer_t buffer = 0;
- // Assert if data isn't filled for vertex data when static draw enabled
- if (desc->usage == GS_GRAPHICS_BUFFER_USAGE_STATIC && !desc->data) {
- gs_println("Error: Vertex buffer desc must contain data when GS_GRAPHICS_BUFFER_USAGE_STATIC set.");
- gs_assert(false);
- }
- glGenBuffers(1, &buffer);
- glBindBuffer(GL_ARRAY_BUFFER, buffer);
- glBufferData(GL_ARRAY_BUFFER, desc->size, desc->data, gsgl_buffer_usage_to_gl_enum(desc->usage));
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- hndl = gs_handle_create(gs_graphics_vertex_buffer_t, gs_slot_array_insert(ogl->vertex_buffers, buffer));
- return hndl;
- }
- GS_API_DECL gs_handle(gs_graphics_index_buffer_t)
- gs_graphics_index_buffer_create_impl(const gs_graphics_index_buffer_desc_t* desc)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- gs_handle(gs_graphics_index_buffer_t) hndl = gs_default_val();
- gsgl_buffer_t buffer = 0;
- // Assert if data isn't filled for vertex data when static draw enabled
- if (desc->usage == GS_GRAPHICS_BUFFER_USAGE_STATIC && !desc->data) {
- gs_println("Error: Index buffer desc must contain data when GS_GRAPHICS_BUFFER_USAGE_STATIC set.");
- gs_assert(false);
- }
- glGenBuffers(1, &buffer);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, desc->size, desc->data, gsgl_buffer_usage_to_gl_enum(desc->usage));
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- hndl = gs_handle_create(gs_graphics_index_buffer_t, gs_slot_array_insert(ogl->index_buffers, buffer));
- return hndl;
- }
- GS_API_DECL gs_handle(gs_graphics_uniform_buffer_t)
- gs_graphics_uniform_buffer_create_impl(const gs_graphics_uniform_buffer_desc_t* desc)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- gs_handle(gs_graphics_uniform_buffer_t) hndl = gs_default_val();
- // Assert if data isn't named
- if (desc->name == NULL) {
- gs_println("Warning: Uniform buffer must be named for Opengl.");
- }
- gsgl_uniform_buffer_t u = gs_default_val();
- memcpy(u.name, desc->name, 64);
- u.size = desc->size;
- u.location = UINT32_MAX;
- // Generate buffer (if needed)
- glGenBuffers(1, &u.ubo);
- glBindBuffer(GL_UNIFORM_BUFFER, u.ubo);
- glBufferData(GL_UNIFORM_BUFFER, u.size, 0, gsgl_buffer_usage_to_gl_enum(desc->usage));
- glBindBuffer(GL_UNIFORM_BUFFER, 0);
- hndl = gs_handle_create(gs_graphics_uniform_buffer_t, gs_slot_array_insert(ogl->uniform_buffers, u));
- return hndl;
- }
- GS_API_DECL gs_handle(gs_graphics_storage_buffer_t)
- gs_graphics_storage_buffer_create_impl(const gs_graphics_storage_buffer_desc_t* desc)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- gs_handle(gs_graphics_storage_buffer_t) hndl = gs_default_val();
- gsgl_storage_buffer_t sbo = gs_default_val();
- if (*desc->name == 0) {
- gs_println("Warning: Storage buffer must be named for Opengl.");
- }
- if (desc->usage == GS_GRAPHICS_BUFFER_USAGE_STATIC && !desc->data) {
- gs_println("Error: Storage buffer desc must contain data when GS_GRAPHICS_BUFFER_USAGE_STATIC set.");
- gs_assert(false);
- }
- glGenBuffers(1, &sbo.buffer);
- CHECK_GL_CORE(
- glBindBuffer(GL_SHADER_STORAGE_BUFFER, sbo.buffer);
- // Check for desc flags to map buffer
- GLbitfield flags = 0x00;
- if (desc->flags & GS_GRAPHICS_BUFFER_FLAG_MAP_PERSISTENT) {flags |= GL_MAP_PERSISTENT_BIT;}
- if (desc->flags & GS_GRAPHICS_BUFFER_FLAG_MAP_COHERENT) {flags |= GL_MAP_PERSISTENT_BIT; flags |= GL_MAP_COHERENT_BIT;}
- if (desc->access & GS_GRAPHICS_ACCESS_READ_ONLY) {flags |= GL_MAP_READ_BIT;}
- else if (desc->access & GS_GRAPHICS_ACCESS_WRITE_ONLY) {flags |= GL_MAP_WRITE_BIT;}
- else if (desc->access & GS_GRAPHICS_ACCESS_READ_WRITE) {flags |= (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT);}
- GLbitfield store_flags = flags;
- if (desc->usage == GS_GRAPHICS_BUFFER_USAGE_DYNAMIC) {
- store_flags |= GL_DYNAMIC_STORAGE_BIT;
- }
- // For now, just do read/write access
- // flags |= GL_MAP_READ_BIT; flags |= GL_MAP_WRITE_BIT;
- glBufferStorage(GL_SHADER_STORAGE_BUFFER, desc->size, desc->data, store_flags);
- // glBufferData(GL_SHADER_STORAGE_BUFFER, desc->size, desc->data, gsgl_buffer_usage_to_gl_enum(desc->usage));
- glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
- // Store mapping
- if (flags & GL_MAP_PERSISTENT_BIT) {
- int32_t err;
- sbo.map = glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, desc->size, flags);
- while ((err = glGetError()) != GL_NO_ERROR) {
- gs_println("GL ERROR: 0x%x: %s", err, glGetString(err));
- }
- }
- GLenum err = glGetError();
- if (err) {
- gs_println("GL ERROR: 0x%x: %s", err, glGetString(err));
- }
- glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
- );
- memcpy(sbo.name, desc->name, 64);
- sbo.access = desc->access;
- sbo.size = desc->size;
- sbo.block_idx = UINT32_MAX;
- hndl = gs_handle_create(gs_graphics_storage_buffer_t, gs_slot_array_insert(ogl->storage_buffers, sbo));
- return hndl;
- }
- GS_API_DECL gs_handle(gs_graphics_framebuffer_t)
- gs_graphics_framebuffer_create_impl(const gs_graphics_framebuffer_desc_t* desc)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- gs_handle(gs_graphics_framebuffer_t) hndl = gs_default_val();
- gsgl_buffer_t buffer = 0;
- glGenFramebuffers(1, &buffer);
- hndl = gs_handle_create(gs_graphics_framebuffer_t, gs_slot_array_insert(ogl->frame_buffers, buffer));
- return hndl;
- }
- #define GSGL_GRAPHICS_SHADER_PIPELINE_GFX 0x01
- #define GSGL_GRAPHICS_SHADER_PIPELINE_COMPUTE 0x02
- #define GSGL_GRAPHICS_MAX_SID 128
- GS_API_DECL gs_handle(gs_graphics_shader_t)
- gs_graphics_shader_create_impl(const gs_graphics_shader_desc_t* desc)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- gsgl_shader_t shader = 0;
- uint32_t pip = 0x00;
- uint32_t sid_ct = 0;
- uint32_t sids[GSGL_GRAPHICS_MAX_SID] = gs_default_val();
- // Create shader program
- shader = glCreateProgram();
- uint32_t ct = (uint32_t)desc->size / (uint32_t)sizeof(gs_graphics_shader_source_desc_t);
- for (uint32_t i = 0; i < ct; ++i)
- {
- if (desc->sources[i].type == GS_GRAPHICS_SHADER_STAGE_VERTEX) pip |= GSGL_GRAPHICS_SHADER_PIPELINE_GFX;
- if (desc->sources[i].type == GS_GRAPHICS_SHADER_STAGE_COMPUTE) pip |= GSGL_GRAPHICS_SHADER_PIPELINE_COMPUTE;
- // Validity Check: Desc must have vertex source if compute not selected. All other source is optional.
- if ((pip & GSGL_GRAPHICS_SHADER_PIPELINE_COMPUTE) && ((pip & GSGL_GRAPHICS_SHADER_PIPELINE_GFX))) {
- gs_println("Error: Cannot have compute and graphics stages for shader program.");
- gs_assert(false);
- }
- uint32_t stage = gsgl_shader_stage_to_gl_stage(desc->sources[i].type);
- uint32_t sid = glCreateShader(stage);
- if (!sid) {
- gs_println ("Error: Failed to allocate memory for shader: '%s': stage: {put stage id here}", desc->name);
- gs_assert(sid);
- }
- // Set source
- glShaderSource(sid, 1, &desc->sources[i].source, NULL);
- // Compile shader
- glCompileShader(sid);
- //Check for errors
- GLint success = 0;
- glGetShaderiv(sid, GL_COMPILE_STATUS, &success);
- if (success == GL_FALSE)
- {
- GLint max_len = 0;
- glGetShaderiv(sid, GL_INFO_LOG_LENGTH, &max_len);
- char* log = (char*)gs_malloc(max_len);
- memset(log, 0, max_len);
- //The max_len includes the NULL character
- glGetShaderInfoLog(sid, max_len, &max_len, log);
-
- // Delete shader.
- glDeleteShader(shader);
- //Provide the infolog
- gs_println("Opengl::opengl_compile_shader::shader: '%s'\nFAILED_TO_COMPILE: %s\n %s", desc->name, log, desc->sources[i].source);
- free(log);
- log = NULL;
- // gs_assert(false);
- return gs_handle_invalid(gs_graphics_shader_t);
- }
- // Attach shader to program
- glAttachShader(shader, sid);
- // Add to shader array
- sids[sid_ct++] = sid;
- }
- // Link shaders into final program
- glLinkProgram(shader);
- //Create info log for errors
- s32 is_linked = 0;
- glGetProgramiv(shader, GL_LINK_STATUS, (s32*)&is_linked);
- if (is_linked == GL_FALSE)
- {
- GLint max_len = 0;
- glGetProgramiv(shader, GL_INFO_LOG_LENGTH, &max_len);
- char* log = (char*)gs_malloc(max_len);
- memset(log, 0, max_len);
- glGetProgramInfoLog(shader, max_len, &max_len, log);
- // Print error
- gs_println("Error: Fail To Link::opengl_link_shaders::shader: '%s', \n%s", desc->name, log);
- // //We don't need the program anymore.
- glDeleteProgram(shader);
- free(log);
- log = NULL;
- // Just assert for now
- gs_assert(false);
- }
- // Free shaders after use
- for (uint32_t i = 0; i < sid_ct; ++i) {
- glDeleteShader(sids[i]);
- }
- // Iterate over uniforms
- /*
- {
- char tmp_name[256] = gs_default_val();
- int32_t count = 0;
- glGetProgramiv(shader, GL_ACTIVE_UNIFORMS, &count);
- gs_println("Active Uniforms: %d\n", count);
- for (uint32_t i = 0; i < count; i++) {
- int32_t sz = 0;
- uint32_t type;
- glGetActiveUniform(shader, (GLuint)i, 256, NULL, &sz, &type, tmp_name);
- gs_println("Uniform #%d Type: %u Name: %s\n", i, type, tmp_name);
- }
- }
- */
- // Add to pool and return handle
- return (gs_handle_create(gs_graphics_shader_t, gs_slot_array_insert(ogl->shaders, shader)));
- }
- GS_API_DECL gs_handle(gs_graphics_renderpass_t)
- gs_graphics_renderpass_create_impl(const gs_graphics_renderpass_desc_t* desc)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- gsgl_renderpass_t pass = gs_default_val();
- // Set fbo
- pass.fbo = desc->fbo;
- // Set color attachments
- uint32_t ct = (uint32_t)desc->color_size / (uint32_t)sizeof(gs_handle(gs_graphics_texture_t));
- for (uint32_t i = 0; i < ct; ++i)
- {
- gs_dyn_array_push(pass.color, desc->color[i]);
- }
- // Set depth attachment
- pass.depth = desc->depth;
- // Create handle and return
- return (gs_handle_create(gs_graphics_renderpass_t, gs_slot_array_insert(ogl->renderpasses, pass)));
- }
- GS_API_DECL gs_handle(gs_graphics_pipeline_t)
- gs_graphics_pipeline_create_impl(const gs_graphics_pipeline_desc_t* desc)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- gsgl_pipeline_t pipe = gs_default_val();
- // Add states
- pipe.blend = desc->blend;
- pipe.depth = desc->depth;
- pipe.raster = desc->raster;
- pipe.stencil = desc->stencil;
- pipe.compute = desc->compute;
- // Add layout
- uint32_t ct = (uint32_t)desc->layout.size / (uint32_t)sizeof(gs_graphics_vertex_attribute_desc_t);
- gs_dyn_array_reserve(pipe.layout, ct);
- for (uint32_t i = 0; i < ct; ++i) {
- gs_dyn_array_push(pipe.layout, desc->layout.attrs[i]);
- }
- // Create handle and return
- return (gs_handle_create(gs_graphics_pipeline_t, gs_slot_array_insert(ogl->pipelines, pipe)));
- }
- // Resource Destruction
- GS_API_DECL void
- gs_graphics_texture_destroy_impl(gs_handle(gs_graphics_texture_t) hndl)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- if (!gs_slot_array_handle_valid(ogl->textures, hndl.id)) return;
- gsgl_texture_t* tex = gs_slot_array_getp(ogl->textures, hndl.id);
- glDeleteTextures(1, &tex->id);
- gs_slot_array_erase(ogl->textures, hndl.id);
- }
- GS_API_DECL void
- gs_graphics_uniform_destroy_impl(gs_handle(gs_graphics_uniform_t) hndl)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- if (!gs_slot_array_handle_valid(ogl->uniforms, hndl.id)) return;
- gsgl_uniform_list_t* ul = gs_slot_array_getp(ogl->uniforms, hndl.id);
- gs_dyn_array_free(ul->uniforms);
- gs_slot_array_erase(ogl->uniforms, hndl.id);
- }
- GS_API_DECL void
- gs_graphics_shader_destroy_impl(gs_handle(gs_graphics_shader_t) hndl)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- if (!gs_slot_array_handle_valid(ogl->shaders, hndl.id)) return;
- glDeleteProgram(gs_slot_array_get(ogl->shaders, hndl.id));
- gs_slot_array_erase(ogl->shaders, hndl.id);
- }
- GS_API_DECL void
- gs_graphics_vertex_buffer_destroy_impl(gs_handle(gs_graphics_vertex_buffer_t) hndl)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- if (!gs_slot_array_handle_valid(ogl->vertex_buffers, hndl.id)) return;
- gsgl_buffer_t buffer = gs_slot_array_get(ogl->vertex_buffers, hndl.id);
- glDeleteBuffers(1, &buffer);
- gs_slot_array_erase(ogl->vertex_buffers, hndl.id);
- }
- GS_API_DECL void
- gs_graphics_index_buffer_destroy_impl(gs_handle(gs_graphics_index_buffer_t) hndl)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- if (!gs_slot_array_handle_valid(ogl->index_buffers, hndl.id)) return;
- gsgl_buffer_t buffer = gs_slot_array_get(ogl->index_buffers, hndl.id);
- glDeleteBuffers(1, &buffer);
- gs_slot_array_erase(ogl->index_buffers, hndl.id);
- }
- GS_API_DECL void
- gs_graphics_uniform_buffer_destroy_impl(gs_handle(gs_graphics_uniform_buffer_t) hndl)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- if (!gs_slot_array_handle_valid(ogl->uniform_buffers, hndl.id)) return;
- gsgl_uniform_buffer_t* u = gs_slot_array_getp(ogl->uniform_buffers, hndl.id);
- // Delete buffer (if needed)
- glDeleteBuffers(1, &u->ubo);
- // Delete from slot array
- gs_slot_array_erase(ogl->uniform_buffers, hndl.id);
- }
- GS_API_DECL void
- gs_graphics_storage_buffer_destroy_impl(gs_handle(gs_graphics_storage_buffer_t) hndl)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- if (!gs_slot_array_handle_valid(ogl->storage_buffers, hndl.id)) return;
- gsgl_storage_buffer_t* sb = gs_slot_array_getp(ogl->storage_buffers, hndl.id);
- // Delete buffer (if needed)
- glDeleteBuffers(1, &sb->buffer);
- // Delete from slot array
- gs_slot_array_erase(ogl->storage_buffers, hndl.id);
- }
- GS_API_DECL void
- gs_graphics_framebuffer_destroy_impl(gs_handle(gs_graphics_framebuffer_t) hndl)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- if (!gs_slot_array_handle_valid(ogl->frame_buffers, hndl.id)) return;
- gsgl_buffer_t buffer = gs_slot_array_get(ogl->frame_buffers, hndl.id);
- glDeleteFramebuffers(1, &buffer);
- gs_slot_array_erase(ogl->frame_buffers, hndl.id);
- }
- GS_API_DECL void
- gs_graphics_renderpass_destroy_impl(gs_handle(gs_graphics_renderpass_t) hndl)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- if (!gs_slot_array_handle_valid(ogl->renderpasses, hndl.id)) return;
- // TODO(john): erase all color attachments from renderpasss
- gs_slot_array_erase(ogl->renderpasses, hndl.id);
- }
- GS_API_DECL void
- gs_graphics_pipeline_destroy_impl(gs_handle(gs_graphics_pipeline_t) hndl)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- if (!gs_slot_array_handle_valid(ogl->pipelines, hndl.id)) return;
- gsgl_pipeline_t* pip = gs_slot_array_getp(ogl->pipelines, hndl.id);
- // Free layout
- gs_dyn_array_free(pip->layout);
- // Erase handles from slot arrays
- gs_slot_array_erase(ogl->pipelines, hndl.id);
- }
- // Resource Query
- GS_API_DECL void
- gs_graphics_pipeline_desc_query(gs_handle(gs_graphics_pipeline_t) hndl, gs_graphics_pipeline_desc_t* out)
- {
- if (!out) return;
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- gsgl_pipeline_t* pip = gs_slot_array_getp(ogl->pipelines, hndl.id);
- // Add states
- out->blend = pip->blend;
- out->depth = pip->depth;
- out->raster = pip->raster;
- out->stencil = pip->stencil;
- out->compute = pip->compute;
- // Add layout
- uint32_t ct = gs_dyn_array_size(pip->layout);
- for (uint32_t i = 0; i < ct; ++i) {
- gs_dyn_array_push(out->layout.attrs, pip->layout[i]);
- }
- }
- GS_API_DECL void
- gs_graphics_texture_desc_query(gs_handle(gs_graphics_texture_t) hndl, gs_graphics_texture_desc_t* out)
- {
- if (!out) return;
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- gsgl_texture_t* tex = gs_slot_array_getp(ogl->textures, hndl.id);
- // Read back pixels
- // NOTE(john): This is currently NOT WORKING.
- if (out->read.width && out->read.height)
- {
- uint32_t type = gsgl_texture_format_to_gl_data_type(tex->desc.format);
- uint32_t format = gsgl_texture_format_to_gl_texture_format(tex->desc.format);
- CHECK_GL_CORE(
- glGetTextureSubImage(tex->id, 0, out->read.x, out->read.y, 0, out->read.width, out->read.height, 1, format, type, out->read.size, out->data);
- // glBindTexture(GL_TEXTURE_2D, tex->id);
- // glGetTexImage(GL_TEXTURE_2D, 0, format, type, out->data);
- // glBindTexture(GL_TEXTURE_2D, 0);
- );
- }
- // Just setting to tex desc for now, since reading texels isn't working correctly.
- *out = tex->desc;
- }
- GS_API_DECL size_t
- gs_graphics_uniform_size_query(gs_handle(gs_graphics_uniform_t) hndl)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- gsgl_uniform_list_t* u = gs_slot_array_getp(ogl->uniforms, hndl.id);
- return u->uniforms[0].size;
- }
- // Resource Updates (main thread only)
- GS_API_DECL void
- gs_graphics_texture_update_impl(gs_handle(gs_graphics_texture_t) hndl, gs_graphics_texture_desc_t* desc)
- {
- if (!desc) return;
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- if (!gs_slot_array_handle_valid(ogl->textures, hndl.id))
- {
- gs_log_warning("Texture handle invalid: %zu", hndl.id);
- return;
- }
- gl_texture_update_internal(desc, hndl.id);
- }
- GS_API_DECL void
- gs_graphics_vertex_buffer_update_impl(gs_handle(gs_graphics_vertex_buffer_t) hndl, gs_graphics_vertex_buffer_desc_t* desc)
- {
- /*
- void __gs_graphics_update_buffer_internal(gs_command_buffer_t* cb,
- uint32_t id,
- gs_graphics_buffer_type type,
- gs_graphics_buffer_usage_type usage,
- size_t sz,
- size_t offset,
- gs_graphics_buffer_update_type update_type,
- void* data)
- {
- // Write command
- gs_byte_buffer_write(&cb->commands, u32, (u32)GS_OPENGL_OP_REQUEST_BUFFER_UPDATE);
- cb->num_commands++;
- // Write handle id
- gs_byte_buffer_write(&cb->commands, uint32_t, id);
- // Write type
- gs_byte_buffer_write(&cb->commands, gs_graphics_buffer_type, type);
- // Write usage
- gs_byte_buffer_write(&cb->commands, gs_graphics_buffer_usage_type, usage);
- // Write data size
- gs_byte_buffer_write(&cb->commands, size_t, sz);
- // Write data offset
- gs_byte_buffer_write(&cb->commands, size_t, offset);
- // Write data update type
- gs_byte_buffer_write(&cb->commands, gs_graphics_buffer_update_type, update_type);
- // Write data
- gs_byte_buffer_write_bulk(&cb->commands, data, sz);
- }
- __gs_graphics_update_buffer_internal(cb, hndl.id, GS_GRAPHICS_BUFFER_VERTEX, desc->usage, desc->size, desc->update.offset, desc->update.type, desc->data);
- */
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- gsgl_buffer_t buffer = gs_slot_array_get(ogl->vertex_buffers, hndl.id);
- glBindBuffer(GL_ARRAY_BUFFER, buffer);
- int32_t glusage = gsgl_buffer_usage_to_gl_enum(desc->usage);
- switch (desc->update.type)
- {
- case GS_GRAPHICS_BUFFER_UPDATE_SUBDATA: glBufferSubData(GL_ARRAY_BUFFER, desc->update.offset, desc->size, desc->data); break;
- default: glBufferData(GL_ARRAY_BUFFER, desc->size, desc->data, glusage); break;
- }
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- }
- GS_API_DECL void
- gs_graphics_index_buffer_update_impl(gs_handle(gs_graphics_index_buffer_t) hndl, gs_graphics_index_buffer_desc_t* desc)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- gsgl_buffer_t buffer = gs_slot_array_get(ogl->index_buffers, hndl.id);
- int32_t glusage = gsgl_buffer_usage_to_gl_enum(desc->usage);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
- switch (desc->update.type) {
- case GS_GRAPHICS_BUFFER_UPDATE_SUBDATA: glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, desc->update.offset, desc->size, desc->data); break;
- default: glBufferData(GL_ELEMENT_ARRAY_BUFFER, desc->size, desc->data, glusage); break;
- }
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- }
- GS_API_DECL void
- gs_graphics_storage_buffer_update_impl(gs_handle(gs_graphics_storage_buffer_t) hndl, gs_graphics_storage_buffer_desc_t* desc)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- gsgl_storage_buffer_t* sbo = gs_slot_array_getp(ogl->storage_buffers, hndl.id);
- if (!sbo)
- {
- gs_println("Warning: Storage buffer %zu not found.", hndl.id);
- return;
- }
- CHECK_GL_CORE(
- glBindBuffer(GL_SHADER_STORAGE_BUFFER, sbo->buffer);
- glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
- switch (desc->update.type) {
- case GS_GRAPHICS_BUFFER_UPDATE_SUBDATA: glBufferSubData(GL_SHADER_STORAGE_BUFFER, desc->update.offset, desc->size, desc->data); break;
- default: glBufferData(GL_SHADER_STORAGE_BUFFER, desc->size, desc->data, gsgl_buffer_usage_to_gl_enum(desc->usage));
- }
- glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
- );
- }
- GS_API_DECL void
- gs_graphics_texture_read_impl(gs_handle(gs_graphics_texture_t) hndl, gs_graphics_texture_desc_t* desc)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- if (!desc) return;
- if (!gs_slot_array_handle_valid(ogl->textures, hndl.id))
- {
- gs_log_warning("Texture handle invalid: %zu", hndl.id);
- }
- gsgl_texture_t* tex = gs_slot_array_getp(ogl->textures, hndl.id);
- // Bind texture
- GLenum target = 0x00;
- switch (tex->desc.type)
- {
- default:
- case GS_GRAPHICS_TEXTURE_2D: {target = GL_TEXTURE_2D;} break;
- case GS_GRAPHICS_TEXTURE_CUBEMAP: {target = GL_TEXTURE_CUBE_MAP;} break;
- }
- uint32_t gl_format = gsgl_texture_format_to_gl_texture_format(tex->desc.format);
- uint32_t gl_type = gsgl_texture_format_to_gl_data_type(tex->desc.format);
- glBindTexture(target, tex->id);
- glReadPixels(
- desc->read.x,
- desc->read.y,
- desc->read.width,
- desc->read.height,
- gl_format,
- gl_type,
- (void*)desc->data[0]
- );
- glBindTexture(target, 0x00);
- }
- GS_API_DECL void*
- gs_graphics_storage_buffer_map_get_impl(gs_handle(gs_graphics_storage_buffer_t) hndl)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- if (!gs_slot_array_handle_valid(ogl->storage_buffers, hndl.id)) {
- gs_log_warning("Storage buffer handle invalid: %zu", hndl.id);
- return NULL;
- }
- gsgl_storage_buffer_t* sbo = gs_slot_array_getp(ogl->storage_buffers, hndl.id);
- return sbo->map;
- }
- GS_API_DECL void
- gs_grapics_storage_buffer_unlock_impl(gs_handle(gs_graphics_storage_buffer_t) hndl)
- {
- // Unlock and return mapped pointer
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- if (!gs_slot_array_handle_valid(ogl->storage_buffers, hndl.id)) {
- gs_log_warning("Storage buffer handle invalid: %zu", hndl.id);
- return;
- }
- gsgl_storage_buffer_t* sbo = gs_slot_array_getp(ogl->storage_buffers, hndl.id);
- // Already unlocked?
- if (sbo->sync) {
- while (1) {
- GLenum wait = glClientWaitSync(sbo->sync, GL_SYNC_FLUSH_COMMANDS_BIT, 1);
- if (wait == GL_ALREADY_SIGNALED || wait == GL_CONDITION_SATISFIED) {
- break;
- }
- }
- }
- // Check for persistence here?...
- if (sbo->map) {
- glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); // Do this via DSA instead...
- glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
- }
- }
- GS_API_DECL void*
- gs_grapics_storage_buffer_lock_impl(gs_handle(gs_graphics_storage_buffer_t) hndl, size_t offset, size_t sz)
- {
- // Lock
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- if (!gs_slot_array_handle_valid(ogl->storage_buffers, hndl.id)) {
- gs_log_warning("Storage buffer handle invalid: %zu", hndl.id);
- return NULL;
- }
- gsgl_storage_buffer_t* sbo = gs_slot_array_getp(ogl->storage_buffers, hndl.id);
- // Already locked?
- if (sbo->sync) {
- glDeleteSync(sbo->sync);
- }
- // Not sure if this is correct...
- sbo->sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
- if (sbo->sync) {
- while (1) {
- GLenum wait = glClientWaitSync(sbo->sync, GL_SYNC_FLUSH_COMMANDS_BIT, 1);
- if (wait == GL_ALREADY_SIGNALED || wait == GL_CONDITION_SATISFIED) {
- break;
- }
- }
- }
- if (!sbo->map) {
- // Get buffer size
- glBindBuffer(GL_SHADER_STORAGE_BUFFER, sbo->buffer);
- GLint buffer_sz = 0;
- glGetBufferParameteriv(GL_SHADER_STORAGE_BUFFER, GL_BUFFER_SIZE, &buffer_sz);
- gs_println("SZ: %zu, requested: %zu", buffer_sz, sz);
- sbo->map = glMapBufferRange(GL_SHADER_STORAGE_BUFFER, (GLintptr)offset, (GLsizeiptr)sz, GL_MAP_READ_BIT);
- GLenum err = glGetError();
- if (err) {
- gs_println("GL ERROR: 0x%x: %s", err, glGetString(err));
- }
- }
- return sbo->map;
- }
- GS_API_DECL void
- gs_storage_buffer_get_data_impl(gs_handle(gs_graphics_storage_buffer_t) hndl, size_t offset, size_t stride, void* out)
- {
- // Lock
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- if (!gs_slot_array_handle_valid(ogl->storage_buffers, hndl.id)) {
- gs_log_warning("Storage buffer handle invalid: %zu", hndl.id);
- return;
- }
- gsgl_storage_buffer_t* sbo = gs_slot_array_getp(ogl->storage_buffers, hndl.id);
- glBindBuffer(GL_SHADER_STORAGE_BUFFER, sbo->buffer);
- glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, offset, stride, out);
- GLenum err = glGetError();
- if (err) {
- // gs_println("GL ERROR: 0x%x: %s", err, glGetString(err));
- }
- glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
- }
- #define __ogl_push_command(CB, OP_CODE, ...)\
- do {\
- gsgl_data_t* DATA = (gsgl_data_t*)gs_subsystem(graphics)->user_data;\
- gs_byte_buffer_write(&CB->commands, u32, (u32)OP_CODE);\
- __VA_ARGS__\
- CB->num_commands++;\
- } while (0)
- /* Command Buffer Ops: Pipeline / Pass / Bind / Draw */
- GS_API_DECL void
- gs_graphics_renderpass_begin(gs_command_buffer_t* cb, gs_handle(gs_graphics_renderpass_t) hndl)
- {
- __ogl_push_command(cb, GS_OPENGL_OP_BEGIN_RENDER_PASS, {
- gs_byte_buffer_write(&cb->commands, uint32_t, hndl.id);
- });
- }
- GS_API_DECL void
- gs_graphics_renderpass_end(gs_command_buffer_t* cb)
- {
- __ogl_push_command(cb, GS_OPENGL_OP_END_RENDER_PASS, {
- // Nothing...
- });
- }
- GS_API_DECL void
- gs_graphics_clear(gs_command_buffer_t* cb, gs_graphics_clear_desc_t* desc)
- {
- __ogl_push_command(cb, GS_OPENGL_OP_CLEAR, {
- uint32_t count = !desc->actions ? 0 : !desc->size ? 1 : (uint32_t)((size_t)desc->size / (size_t)sizeof(gs_graphics_clear_action_t));
- gs_byte_buffer_write(&cb->commands, uint32_t, count);
- for (uint32_t i = 0; i < count; ++i) {
- gs_byte_buffer_write(&cb->commands, gs_graphics_clear_action_t, desc->actions[i]);
- }
- });
- }
- GS_API_DECL void
- gs_graphics_set_viewport(gs_command_buffer_t* cb, uint32_t x, uint32_t y, uint32_t w, uint32_t h)
- {
- __ogl_push_command(cb, GS_OPENGL_OP_SET_VIEWPORT, {
- gs_byte_buffer_write(&cb->commands, uint32_t, x);
- gs_byte_buffer_write(&cb->commands, uint32_t, y);
- gs_byte_buffer_write(&cb->commands, uint32_t, w);
- gs_byte_buffer_write(&cb->commands, uint32_t, h);
- });
- }
- GS_API_DECL void
- gs_graphics_set_view_scissor(gs_command_buffer_t* cb, uint32_t x, uint32_t y, uint32_t w, uint32_t h)
- {
- __ogl_push_command(cb, GS_OPENGL_OP_SET_VIEW_SCISSOR, {
- gs_byte_buffer_write(&cb->commands, uint32_t, x);
- gs_byte_buffer_write(&cb->commands, uint32_t, y);
- gs_byte_buffer_write(&cb->commands, uint32_t, w);
- gs_byte_buffer_write(&cb->commands, uint32_t, h);
- });
- }
- GS_API_DECL void
- gs_graphics_texture_request_update(gs_command_buffer_t* cb, gs_handle(gs_graphics_texture_t) hndl, gs_graphics_texture_desc_t* desc)
- {
- // Write command
- gs_byte_buffer_write(&cb->commands, uint32_t, (uint32_t)GS_OPENGL_OP_REQUEST_TEXTURE_UPDATE);
- cb->num_commands++;
- uint32_t num_comps = 0;
- size_t data_type_size = 0;
- size_t total_size = 0;
- switch(desc->format)
- {
- default:
- case GS_GRAPHICS_TEXTURE_FORMAT_RGBA8: num_comps = 4; data_type_size = sizeof(uint8_t); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_RGB8: num_comps = 3; data_type_size = sizeof(uint8_t); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_A8: num_comps = 1; data_type_size = sizeof(uint8_t); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_R8: num_comps = 1; data_type_size = sizeof(uint8_t); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_R32UI: num_comps = 1; data_type_size = sizeof(uint32_t); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_R16UI: num_comps = 1; data_type_size = sizeof(uint16_t); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_RGBA16F: num_comps = 4; data_type_size = sizeof(float); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_RGBA32F: num_comps = 4; data_type_size = sizeof(float); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH8: num_comps = 1; data_type_size = sizeof(float); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH16: num_comps = 1; data_type_size = sizeof(float); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH24: num_comps = 1; data_type_size = sizeof(float); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH32F: num_comps = 1; data_type_size = sizeof(float); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH24_STENCIL8: num_comps = 1; data_type_size = sizeof(uint32_t); break;
- case GS_GRAPHICS_TEXTURE_FORMAT_DEPTH32F_STENCIL8: num_comps = 1; data_type_size = sizeof(float) + sizeof(uint8_t); break;
- // NOTE(john): Because Apple is a shit company, I have to section this off and provide support for 4.1 only features.
- // case GS_GRAPHICS_TEXTURE_FORMAT_STENCIL8: glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT8, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, data); break;
- }
- total_size = desc->width * desc->height * num_comps * data_type_size;
- gs_byte_buffer_write(&cb->commands, uint32_t, hndl.id);
- gs_byte_buffer_write(&cb->commands, gs_graphics_texture_desc_t, *desc);
- gs_byte_buffer_write(&cb->commands, size_t, total_size);
- gs_byte_buffer_write_bulk(&cb->commands, *desc->data, total_size);
- }
- void __gs_graphics_update_buffer_internal(gs_command_buffer_t* cb,
- uint32_t id,
- gs_graphics_buffer_type type,
- gs_graphics_buffer_usage_type usage,
- size_t sz,
- size_t offset,
- gs_graphics_buffer_update_type update_type,
- void* data)
- {
- // Write command
- gs_byte_buffer_write(&cb->commands, u32, (u32)GS_OPENGL_OP_REQUEST_BUFFER_UPDATE);
- cb->num_commands++;
- // Write handle id
- gs_byte_buffer_write(&cb->commands, uint32_t, id);
- // Write type
- gs_byte_buffer_write(&cb->commands, gs_graphics_buffer_type, type);
- // Write usage
- gs_byte_buffer_write(&cb->commands, gs_graphics_buffer_usage_type, usage);
- // Write data size
- gs_byte_buffer_write(&cb->commands, size_t, sz);
- // Write data offset
- gs_byte_buffer_write(&cb->commands, size_t, offset);
- // Write data update type
- gs_byte_buffer_write(&cb->commands, gs_graphics_buffer_update_type, update_type);
- // Write data
- gs_byte_buffer_write_bulk(&cb->commands, data, sz);
- }
- GS_API_DECL void
- gs_graphics_vertex_buffer_request_update(gs_command_buffer_t* cb, gs_handle(gs_graphics_vertex_buffer_t) hndl, gs_graphics_vertex_buffer_desc_t* desc)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- // Return if handle not valid
- if (!hndl.id) return;
- __gs_graphics_update_buffer_internal(cb, hndl.id, GS_GRAPHICS_BUFFER_VERTEX, desc->usage, desc->size, desc->update.offset, desc->update.type, desc->data);
- }
- GS_API_DECL void
- gs_graphics_index_buffer_request_update(gs_command_buffer_t* cb, gs_handle(gs_graphics_index_buffer_t) hndl, gs_graphics_index_buffer_desc_t* desc)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- // Return if handle not valid
- if (!hndl.id) return;
- __gs_graphics_update_buffer_internal(cb, hndl.id, GS_GRAPHICS_BUFFER_INDEX, desc->usage, desc->size, desc->update.offset, desc->update.type, desc->data);
- }
- GS_API_DECL void
- gs_graphics_uniform_buffer_request_update(gs_command_buffer_t* cb, gs_handle(gs_graphics_uniform_buffer_t) hndl, gs_graphics_uniform_buffer_desc_t* desc)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- // Return if handle not valid
- if (!hndl.id) return;
- __gs_graphics_update_buffer_internal(cb, hndl.id, GS_GRAPHICS_BUFFER_UNIFORM, desc->usage, desc->size, desc->update.offset, desc->update.type, desc->data);
- }
- GS_API_DECL void
- gs_graphics_storage_buffer_request_update(gs_command_buffer_t* cb, gs_handle(gs_graphics_storage_buffer_t) hndl, gs_graphics_storage_buffer_desc_t* desc)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- // Return if handle not valid
- if (!hndl.id) return;
- __gs_graphics_update_buffer_internal(cb, hndl.id, GS_GRAPHICS_BUFFER_SHADER_STORAGE, desc->usage, desc->size, desc->update.offset, desc->update.type, desc->data);
- }
- void gs_graphics_apply_bindings(gs_command_buffer_t* cb, gs_graphics_bind_desc_t* binds)
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- // Increment commands
- gs_byte_buffer_write(&cb->commands, u32, (u32)GS_OPENGL_OP_APPLY_BINDINGS);
- cb->num_commands++;
-
- // __ogl_push_command(cb, GS_OPENGL_OP_APPLY_BINDINGS,
- {
- // Get counts from buffers
- uint32_t vct = binds->vertex_buffers.desc ? binds->vertex_buffers.size ? binds->vertex_buffers.size / sizeof(gs_graphics_bind_vertex_buffer_desc_t) : 1 : 0;
- uint32_t ict = binds->index_buffers.desc ? binds->index_buffers.size ? binds->index_buffers.size / sizeof(gs_graphics_bind_index_buffer_desc_t) : 1 : 0;
- uint32_t uct = binds->uniform_buffers.desc ? binds->uniform_buffers.size ? binds->uniform_buffers.size / sizeof(gs_graphics_bind_uniform_buffer_desc_t) : 1 : 0;
- uint32_t pct = binds->uniforms.desc ? binds->uniforms.size ? binds->uniforms.size / sizeof(gs_graphics_bind_uniform_desc_t) : 1 : 0;
- uint32_t ibc = binds->image_buffers.desc ? binds->image_buffers.size ? binds->image_buffers.size / sizeof(gs_graphics_bind_image_buffer_desc_t) : 1 : 0;
- uint32_t sbc = binds->storage_buffers.desc ? binds->storage_buffers.size ? binds->storage_buffers.size / sizeof(gs_graphics_bind_storage_buffer_desc_t) : 1 : 0;
- // Determine total count to write into command buffer
- uint32_t ct = vct + ict + uct + pct + ibc + sbc;
- gs_byte_buffer_write(&cb->commands, uint32_t, ct);
- // Determine if need to clear any previous vertex buffers (if vct != 0)
- gs_byte_buffer_write(&cb->commands, bool, (vct != 0));
- // Vertex buffers
- for (uint32_t i = 0; i < vct; ++i)
- {
- gs_graphics_bind_vertex_buffer_desc_t* decl = &binds->vertex_buffers.desc[i];
- gs_byte_buffer_write(&cb->commands, gs_graphics_bind_type, GS_GRAPHICS_BIND_VERTEX_BUFFER);
- gs_byte_buffer_write(&cb->commands, uint32_t, decl->buffer.id);
- gs_byte_buffer_write(&cb->commands, size_t, decl->offset);
- gs_byte_buffer_write(&cb->commands, gs_graphics_vertex_data_type, decl->data_type);
- }
- // Index buffers
- for (uint32_t i = 0; i < ict; ++i)
- {
- gs_graphics_bind_index_buffer_desc_t* decl = &binds->index_buffers.desc[i];
- gs_byte_buffer_write(&cb->commands, gs_graphics_bind_type, GS_GRAPHICS_BIND_INDEX_BUFFER);
- gs_byte_buffer_write(&cb->commands, uint32_t, decl->buffer.id);
- }
- // Uniform buffers
- for (uint32_t i = 0; i < uct; ++i)
- {
- gs_graphics_bind_uniform_buffer_desc_t* decl = &binds->uniform_buffers.desc[i];
- uint32_t id = decl->buffer.id;
- size_t sz = (size_t)(gs_slot_array_getp(ogl->uniform_buffers, id))->size;
- gs_byte_buffer_write(&cb->commands, gs_graphics_bind_type, GS_GRAPHICS_BIND_UNIFORM_BUFFER);
- gs_byte_buffer_write(&cb->commands, uint32_t, decl->buffer.id);
- gs_byte_buffer_write(&cb->commands, uint32_t, decl->binding);
- gs_byte_buffer_write(&cb->commands, size_t, decl->range.offset);
- gs_byte_buffer_write(&cb->commands, size_t, decl->range.size);
- }
- // Image buffers
- for (uint32_t i = 0; i < ibc; ++i)
- {
- gs_graphics_bind_image_buffer_desc_t* decl = &binds->image_buffers.desc[i];
- gs_byte_buffer_write(&cb->commands, gs_graphics_bind_type, GS_GRAPHICS_BIND_IMAGE_BUFFER);
- gs_byte_buffer_write(&cb->commands, uint32_t, decl->tex.id);
- gs_byte_buffer_write(&cb->commands, uint32_t, decl->binding);
- gs_byte_buffer_write(&cb->commands, gs_graphics_access_type, decl->access);
- }
- // Uniforms
- for (uint32_t i = 0; i < pct; ++i)
- {
- gs_graphics_bind_uniform_desc_t* decl = &binds->uniforms.desc[i];
- // Get size from uniform list
- size_t sz = gs_slot_array_getp(ogl->uniforms, decl->uniform.id)->size;
- gs_byte_buffer_write(&cb->commands, gs_graphics_bind_type, GS_GRAPHICS_BIND_UNIFORM);
- gs_byte_buffer_write(&cb->commands, uint32_t, decl->uniform.id);
- gs_byte_buffer_write(&cb->commands, size_t, sz);
- gs_byte_buffer_write(&cb->commands, uint32_t, decl->binding);
- gs_byte_buffer_write_bulk(&cb->commands, decl->data, sz);
- }
- // Storage buffers
- CHECK_GL_CORE(
- for (uint32_t i = 0; i < sbc; ++i)
- {
- gs_graphics_bind_storage_buffer_desc_t* decl = &binds->storage_buffers.desc[i];
- gs_byte_buffer_write(&cb->commands, gs_graphics_bind_type, GS_GRAPHICS_BIND_STORAGE_BUFFER);
- gs_byte_buffer_write(&cb->commands, uint32_t, decl->buffer.id);
- gs_byte_buffer_write(&cb->commands, uint32_t, decl->binding);
- gs_byte_buffer_write(&cb->commands, size_t, decl->range.offset);
- gs_byte_buffer_write(&cb->commands, size_t, decl->range.size);
- }
- );
- };
- }
- void gs_graphics_pipeline_bind(gs_command_buffer_t* cb, gs_handle(gs_graphics_pipeline_t) hndl)
- {
- // NOTE(john): Not sure if this is safe in the future, since the data for pipelines is on the main thread and MIGHT be tampered with on a separate thread.
- __ogl_push_command(cb, GS_OPENGL_OP_BIND_PIPELINE, {
- gs_byte_buffer_write(&cb->commands, uint32_t, hndl.id);
- });
- }
- void gs_graphics_draw(gs_command_buffer_t* cb, gs_graphics_draw_desc_t* desc)
- {
- __ogl_push_command(cb, GS_OPENGL_OP_DRAW, {
- gs_byte_buffer_write(&cb->commands, uint32_t, desc->start);
- gs_byte_buffer_write(&cb->commands, uint32_t, desc->count);
- gs_byte_buffer_write(&cb->commands, uint32_t, desc->instances);
- gs_byte_buffer_write(&cb->commands, uint32_t, desc->base_vertex);
- gs_byte_buffer_write(&cb->commands, uint32_t, desc->range.start);
- gs_byte_buffer_write(&cb->commands, uint32_t, desc->range.end);
- });
- }
- void gs_graphics_dispatch_compute(gs_command_buffer_t* cb, uint32_t num_x_groups, uint32_t num_y_groups, uint32_t num_z_groups)
- {
- __ogl_push_command(cb, GS_OPENGL_OP_DISPATCH_COMPUTE, {
- gs_byte_buffer_write(&cb->commands, uint32_t, num_x_groups);
- gs_byte_buffer_write(&cb->commands, uint32_t, num_y_groups);
- gs_byte_buffer_write(&cb->commands, uint32_t, num_z_groups);
- });
- }
- /* Submission (Main Thread) */
- void gs_graphics_command_buffer_submit_impl(gs_command_buffer_t* cb)
- {
- /*
- // Structure of command:
- - Op code
- - Data packet
- */
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- // Set read position of buffer to beginning
- gs_byte_buffer_seek_to_beg(&cb->commands);
- // For each command in buffer
- gs_for_range(cb->num_commands)
- {
- // Read in op code of command
- gs_byte_buffer_readc(&cb->commands, gs_opengl_op_code_type, op_code);
- switch (op_code)
- {
- case GS_OPENGL_OP_BEGIN_RENDER_PASS:
- {
- // Bind render pass stuff
- gs_byte_buffer_readc(&cb->commands, uint32_t, rpid);
- // If render pass exists, then we'll bind frame buffer and attachments
- if (rpid && gs_slot_array_exists(ogl->renderpasses, rpid))
- {
- gsgl_renderpass_t* rp = gs_slot_array_getp(ogl->renderpasses, rpid);
- // Bind frame buffer since it actually exists
- if (rp->fbo.id && gs_slot_array_exists(ogl->frame_buffers, rp->fbo.id))
- {
- // Bind frame buffer
- glBindFramebuffer(GL_FRAMEBUFFER, gs_slot_array_get(ogl->frame_buffers, rp->fbo.id));
- // Bind color attachments
- for (uint32_t r = 0; r < gs_dyn_array_size(rp->color); ++r)
- {
- uint32_t cid = rp->color[r].id;
- if (cid && gs_slot_array_exists(ogl->textures, cid))
- {
- gsgl_texture_t* rt = gs_slot_array_getp(ogl->textures, cid);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + r, GL_TEXTURE_2D, rt->id, 0);
- }
- }
- // Bind depth attachment
- {
- uint32_t depth_id = rp->depth.id;
- if (depth_id && gs_slot_array_exists(ogl->textures, depth_id))
- {
- gsgl_texture_t* rt = gs_slot_array_getp(ogl->textures, depth_id);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->id, 0);
- }
- }
- }
- }
- } break;
- case GS_OPENGL_OP_END_RENDER_PASS:
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- gsgl_reset_data_cache(&ogl->cache);
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- CHECK_GL_CORE(
- glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0);
- );
- glDisable(GL_SCISSOR_TEST);
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_STENCIL_TEST);
- glDisable(GL_BLEND);
- } break;
- case GS_OPENGL_OP_CLEAR:
- {
- // Actions
- gs_byte_buffer_readc(&cb->commands, uint32_t, action_count);
- for (uint32_t j = 0; j < action_count; ++j)
- {
- gs_byte_buffer_readc(&cb->commands, gs_graphics_clear_action_t, action);
- // No clear
- if (action.flag & GS_GRAPHICS_CLEAR_NONE) {
- continue;
- }
- uint32_t bit = 0x00;
- if (action.flag & GS_GRAPHICS_CLEAR_COLOR || action.flag == 0x00) {
- glClearColor(action.color[0], action.color[1], action.color[2], action.color[3]);
- bit |= GL_COLOR_BUFFER_BIT;
- }
- if (action.flag & GS_GRAPHICS_CLEAR_DEPTH || action.flag == 0x00) {
- bit |= GL_DEPTH_BUFFER_BIT;
- }
- if (action.flag & GS_GRAPHICS_CLEAR_STENCIL || action.flag == 0x00) {
- bit |= GL_STENCIL_BUFFER_BIT;
- glStencilMask(~0);
- }
- glClear(bit);
- }
- } break;
- case GS_OPENGL_OP_SET_VIEWPORT:
- {
- gs_byte_buffer_readc(&cb->commands, uint32_t, x);
- gs_byte_buffer_readc(&cb->commands, uint32_t, y);
- gs_byte_buffer_readc(&cb->commands, uint32_t, w);
- gs_byte_buffer_readc(&cb->commands, uint32_t, h);
- glViewport(x, y, w, h);
- } break;
- case GS_OPENGL_OP_SET_VIEW_SCISSOR:
- {
- gs_byte_buffer_readc(&cb->commands, uint32_t, x);
- gs_byte_buffer_readc(&cb->commands, uint32_t, y);
- gs_byte_buffer_readc(&cb->commands, uint32_t, w);
- gs_byte_buffer_readc(&cb->commands, uint32_t, h);
- glEnable(GL_SCISSOR_TEST);
- glScissor(x, y, w, h);
- } break;
- case GS_OPENGL_OP_APPLY_BINDINGS:
- {
- gs_byte_buffer_readc(&cb->commands, uint32_t, ct);
- // Determine if need to clear any previous vertex buffers here
- gs_byte_buffer_readc(&cb->commands, bool, clear_vertex_buffers);
- // Clear previous vertex decls if necessary
- if (clear_vertex_buffers) {
- gs_dyn_array_clear(ogl->cache.vdecls);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- }
- for (uint32_t i = 0; i < ct; ++i)
- {
- gs_byte_buffer_readc(&cb->commands, gs_graphics_bind_type, type);
- switch (type)
- {
- case GS_GRAPHICS_BIND_VERTEX_BUFFER:
- {
- gs_byte_buffer_readc(&cb->commands, uint32_t, id);
- gs_byte_buffer_readc(&cb->commands, size_t, offset);
- gs_byte_buffer_readc(&cb->commands, gs_graphics_vertex_data_type, data_type);
- if (!id || !gs_slot_array_exists(ogl->vertex_buffers, id))
- {
- /*
- gs_timed_action(1000, {
- gs_println("Warning:Opengl:BindBindings:VertexBuffer %d does not exist.", id);
- continue;
- });
- */
- }
- // Grab vbo to bind
- gsgl_buffer_t vbo = gs_slot_array_get(ogl->vertex_buffers, id);
- // If the data type is non-interleaved, then push size into vertex buffer decl
- gsgl_vertex_buffer_decl_t vbo_decl = gs_default_val();
- vbo_decl.vbo = vbo;
- vbo_decl.data_type = data_type;
- vbo_decl.offset = offset;
- // Cache vertex buffer for later use
- gs_dyn_array_push(ogl->cache.vdecls, vbo_decl);
- } break;
- case GS_GRAPHICS_BIND_INDEX_BUFFER:
- {
- gs_byte_buffer_readc(&cb->commands, uint32_t, id);
- if (!gs_slot_array_exists(ogl->index_buffers, id))
- {
- /*
- gs_timed_action(1000, {
- gs_println("Warning:Opengl:BindBindings:IndexBuffer %d does not exist.", id);
- });
- */
- }
- else
- {
- gsgl_buffer_t ibo = gs_slot_array_get(ogl->index_buffers, id);
- // Store in cache
- ogl->cache.ibo = id;
- }
- } break;
- case GS_GRAPHICS_BIND_UNIFORM:
- {
- // Get size from uniform list
- gs_byte_buffer_readc(&cb->commands, uint32_t, id);
- // Read data size for uniform list
- gs_byte_buffer_readc(&cb->commands, size_t, sz);
- // Read binding from uniform list (could make this a binding list? not sure how to handle this)
- gs_byte_buffer_readc(&cb->commands, uint32_t, binding);
- // Check buffer id. If invalid, then we can't operate, and instead just need to pass over the data.
- if (!id || !gs_slot_array_exists(ogl->uniforms, id)) {
- /*
- gs_timed_action(1000, {
- gs_println("Warning:Bind Uniform:Uniform %d does not exist.", id);
- });
- */
- gs_byte_buffer_advance_position(&cb->commands, sz);
- continue;
- }
- // Grab currently bound pipeline (TODO(john): assert if this isn't valid)
- if (!ogl->cache.pipeline.id || !gs_slot_array_exists(ogl->pipelines, ogl->cache.pipeline.id)){
- /*
- gs_timed_action(1000, {
- gs_println("Warning:Bind Uniform Buffer:Pipeline %d does not exist.", ogl->cache.pipeline.id);
- });
- */
- gs_byte_buffer_advance_position(&cb->commands, sz);
- continue;
- }
- gsgl_pipeline_t* pip = gs_slot_array_getp(ogl->pipelines, ogl->cache.pipeline.id);
- // Get uniform
- gsgl_uniform_list_t* ul = gs_slot_array_getp(ogl->uniforms, id);
- // Get bound shader from pipeline (either compute or raster)
- uint32_t sid = pip->compute.shader.id ? pip->compute.shader.id : pip->raster.shader.id;
- // Check uniform location. If UINT32_T max, then must construct and place location
- for (uint32_t ui = 0; ui < gs_dyn_array_size(ul->uniforms); ++ui)
- {
- gsgl_uniform_t* u = &ul->uniforms[ui];
- // Searching for location if not bound or sid doesn't match previous use
- if ((u->location == UINT32_MAX && u->location != UINT32_MAX - 1) || u->sid != pip->raster.shader.id)
- {
- if (!sid || !gs_slot_array_exists(ogl->shaders, sid)) {
- /*
- gs_timed_action(1000, {
- gs_println("Warning:Bind Uniform:Shader %d does not exist.", sid);
- });
- */
- // Advance by size of uniform
- gs_byte_buffer_advance_position(&cb->commands, sz);
- continue;
- }
- gsgl_shader_t shader = gs_slot_array_get(ogl->shaders, sid);
- // Construct temp name, concat with base name + uniform field name
- char name[256] = gs_default_val();
- memcpy(name, ul->name, 64);
- gs_snprintfc(UTMP, 256, "%s%s", ul->name, u->name);
- memcpy(name, UTMP, 256);
- // Grab location of uniform based on name
- u->location = glGetUniformLocation(shader, *name ? name : "__EMPTY_UNIFORM_NAME");
- if (u->location >= UINT32_MAX) {
- gs_println("Warning: Bind Uniform: Uniform not found: \"%s\"", name);
- u->location = UINT32_MAX - 1;
- }
- u->sid = pip->raster.shader.id;
- }
- // Switch on uniform type to upload data
- switch (u->type)
- {
- case GSGL_UNIFORMTYPE_FLOAT:
- {
- // Need to read bulk data for array.
- gs_assert(u->size == sizeof(float));
- gs_dyn_array_clear(ogl->uniform_data.flt);
- uint32_t ct = u->count ? u->count : 1;
- size_t sz = ct * u->size;
- gs_for_range(ct) {
- gs_byte_buffer_readc(&cb->commands, float, v);
- gs_dyn_array_push(ogl->uniform_data.flt, v);
- }
- glUniform1fv(u->location, ct, ogl->uniform_data.flt);
- } break;
- case GSGL_UNIFORMTYPE_INT:
- {
- gs_assert(u->size == sizeof(int32_t));
- gs_dyn_array_clear(ogl->uniform_data.i32);
- uint32_t ct = u->count ? u->count : 1;
- size_t sz = ct * u->size;
- gs_for_range(ct) {
- gs_byte_buffer_readc(&cb->commands, int32_t, v);
- gs_dyn_array_push(ogl->uniform_data.i32, v);
- }
- glUniform1iv(u->location, ct, ogl->uniform_data.i32);
- } break;
- case GSGL_UNIFORMTYPE_VEC2:
- {
- gs_assert(u->size == sizeof(gs_vec2));
- gs_dyn_array_clear(ogl->uniform_data.vec2);
- uint32_t ct = u->count ? u->count : 1;
- size_t sz = ct * u->size;
- gs_for_range(ct) {
- gs_byte_buffer_readc(&cb->commands, gs_vec2, v);
- gs_dyn_array_push(ogl->uniform_data.vec2, v);
- }
- glUniform2fv(u->location, ct, (float*)ogl->uniform_data.vec2);
- } break;
- case GSGL_UNIFORMTYPE_VEC3:
- {
- gs_assert(u->size == sizeof(gs_vec3));
- gs_dyn_array_clear(ogl->uniform_data.vec3);
- uint32_t ct = u->count ? u->count : 1;
- size_t sz = ct * u->size;
- gs_for_range(ct) {
- gs_byte_buffer_readc(&cb->commands, gs_vec3, v);
- gs_dyn_array_push(ogl->uniform_data.vec3, v);
- }
- glUniform3fv(u->location, ct, (float*)ogl->uniform_data.vec3);
- } break;
- case GSGL_UNIFORMTYPE_VEC4:
- {
- gs_assert(u->size == sizeof(gs_vec4));
- gs_dyn_array_clear(ogl->uniform_data.vec4);
- uint32_t ct = u->count ? u->count : 1;
- size_t sz = ct * u->size;
- gs_for_range(ct) {
- gs_byte_buffer_readc(&cb->commands, gs_vec4, v);
- gs_dyn_array_push(ogl->uniform_data.vec4, v);
- }
- glUniform4fv(u->location, ct, (float*)ogl->uniform_data.vec4);
- } break;
- case GSGL_UNIFORMTYPE_MAT4:
- {
- gs_assert(u->size == sizeof(gs_mat4));
- gs_dyn_array_clear(ogl->uniform_data.mat4);
- uint32_t ct = u->count ? u->count : 1;
- size_t sz = ct * u->size;
- gs_for_range(ct) {
- gs_byte_buffer_readc(&cb->commands, gs_mat4, v);
- gs_dyn_array_push(ogl->uniform_data.mat4, v);
- }
- glUniformMatrix4fv(u->location, ct, false, (float*)ogl->uniform_data.mat4);
- } break;
- case GSGL_UNIFORMTYPE_SAMPLERCUBE:
- case GSGL_UNIFORMTYPE_SAMPLER2D:
- {
- gs_assert(u->size == sizeof(gs_handle(gs_graphics_texture_t)));
- uint32_t ct = u->count ? u->count : 1;
- int32_t binds[128] = gs_default_val();
- for (uint32_t i = 0; (i < ct && i < 128); ++i) // Max of 128 texture binds. Get real.
- {
- gs_byte_buffer_read_bulkc(&cb->commands, gs_handle(gs_graphics_texture_t), v, u->size);
- // Get texture, also need binding, but will worry about that in a bit
- gsgl_texture_t* tex = gs_slot_array_getp(ogl->textures, v.id);
- // Activate texture slot
- glActiveTexture(GL_TEXTURE0 + binding);
- // Bind texture
- GLenum target = 0x00;
- switch (tex->desc.type)
- {
- default:
- case GS_GRAPHICS_TEXTURE_2D: {target = GL_TEXTURE_2D;} break;
- case GS_GRAPHICS_TEXTURE_CUBEMAP: {target = GL_TEXTURE_CUBE_MAP;} break;
- }
- glBindTexture(target, tex->id);
- binds[i] = (int32_t)binding++;
- }
- // Bind uniforms
- glUniform1iv(u->location, ct, (int32_t*)binds);
- } break;
- default: {
- // Shouldn't hit here
- gs_println("Assert: Bind Uniform: Invalid uniform type specified.");
- gs_assert(false);
- } break;
- }
- }
- } break;
- case GS_GRAPHICS_BIND_UNIFORM_BUFFER:
- {
- // Read slot id of uniform buffer
- gs_byte_buffer_readc(&cb->commands, uint32_t, id);
- // Read binding
- gs_byte_buffer_readc(&cb->commands, uint32_t, binding);
- // Read range offset
- gs_byte_buffer_readc(&cb->commands, size_t, range_offset);
- // Read range size
- gs_byte_buffer_readc(&cb->commands, size_t, range_size);
- // Check buffer id. If invalid, then we can't operate, and instead just need to pass over the data.
- if (!id || !gs_slot_array_exists(ogl->uniform_buffers, id)) {
- /*
- gs_timed_action(1000, {
- gs_println("Warning:Bind Uniform Buffer:Uniform %d does not exist.", id);
- });
- */
- continue;
- }
- // Grab currently bound pipeline (TODO(john): assert if this isn't valid)
- if (!ogl->cache.pipeline.id || !gs_slot_array_exists(ogl->pipelines, ogl->cache.pipeline.id)){
- /*
- gs_timed_action(1000, {
- gs_println("Warning:Bind Uniform Buffer:Pipeline %d does not exist.", ogl->cache.pipeline.id);
- });
- */
- continue;
- }
- gsgl_pipeline_t* pip = gs_slot_array_getp(ogl->pipelines, ogl->cache.pipeline.id);
- // Get uniform
- gsgl_uniform_buffer_t* u = gs_slot_array_getp(ogl->uniform_buffers, id);
- // Get bound shader from pipeline (either compute or raster)
- uint32_t sid = pip->compute.shader.id ? pip->compute.shader.id : pip->raster.shader.id;
- // Check uniform location.
- // If UINT32_T max, then must construct and place location, or if shader id doesn't match previously used shader with this uniform
- // TODO(john): To avoid constant lookups in this case, allow for shaders to hold uniform handles references instead.
- if ((u->location == UINT32_MAX && u->location != UINT32_MAX - 1) || u->sid != pip->raster.shader.id)
- {
- if (!sid || !gs_slot_array_exists(ogl->shaders, sid)) {
- /*
- gs_timed_action(1000, {
- gs_println("Warning:Bind Uniform Buffer:Shader %d does not exist.", sid);
- });
- */
- continue;
- }
- gsgl_shader_t shader = gs_slot_array_get(ogl->shaders, sid);
- // Get uniform location based on name and bound shader
- u->location = glGetUniformBlockIndex(shader, *u->name ? u->name : "__EMPTY_UNIFORM_NAME");
- // Set binding for uniform block
- glUniformBlockBinding(shader, u->location, binding);
- if (u->location >= UINT32_MAX) {
- gs_println("Warning: Bind Uniform Buffer: Uniform not found: \"%s\"", u->name);
- u->location = UINT32_MAX - 1;
- }
- u->sid = pip->raster.shader.id;
- }
- glBindBufferRange(GL_UNIFORM_BUFFER, binding, u->ubo, range_offset, range_size ? range_size : u->size);
- } break;
- case GS_GRAPHICS_BIND_STORAGE_BUFFER:
- {
- gs_byte_buffer_readc(&cb->commands, uint32_t, sb_slot_id);
- gs_byte_buffer_readc(&cb->commands, uint32_t, binding);
- gs_byte_buffer_readc(&cb->commands, size_t, range_offset);
- gs_byte_buffer_readc(&cb->commands, size_t, range_size);
- // Grab storage buffer from id
- if (!sb_slot_id || !gs_slot_array_exists(ogl->storage_buffers, sb_slot_id)) {
- /*
- gs_timed_action(1000, {
- gs_println("Warning:Bind Storage Buffer:Storage Buffer %d does not exist.", sb_slot_id);
- });
- */
- continue;
- }
- // Grab currently bound pipeline (TODO(john): assert if this isn't valid)
- if (!ogl->cache.pipeline.id || !gs_slot_array_exists(ogl->pipelines, ogl->cache.pipeline.id)){
- /*
- gs_timed_action(1000, {
- gs_println("Warning:Bind Storage Buffer:Pipeline %d does not exist or is not bound.", ogl->cache.pipeline.id);
- });
- */
- continue;
- }
- gsgl_pipeline_t* pip = gs_slot_array_getp(ogl->pipelines, ogl->cache.pipeline.id);
- gsgl_storage_buffer_t* sbo = gs_slot_array_getp(ogl->storage_buffers, sb_slot_id);
- // Get bound shader from pipeline (either compute or raster)
- uint32_t sid = pip->compute.shader.id ? pip->compute.shader.id : pip->raster.shader.id;
- if (!sid || !gs_slot_array_exists(ogl->shaders, sid)) {
- /*
- gs_timed_action(1000, {
- gs_println("Warning:Bind Uniform Buffer:Shader %d does not exist.", sid);
- });
- */
- continue;
- }
- gsgl_shader_t shader = gs_slot_array_get(ogl->shaders, sid);
- if ((sbo->block_idx == UINT32_MAX && sbo->block_idx != UINT32_MAX - 1))
- {
- // Get uniform location based on name and bound shader
- CHECK_GL_CORE(
- sbo->block_idx = glGetProgramResourceIndex(shader, GL_SHADER_STORAGE_BLOCK, *sbo->name ? sbo->name : "__EMPTY_BUFFER_NAME");
- int32_t params[1];
- GLenum props[1] = {GL_BUFFER_BINDING};
- glGetProgramResourceiv(shader, GL_SHADER_STORAGE_BLOCK, sbo->block_idx, 1, props, 1, NULL, params);
- sbo->location = (uint32_t)params[0];
- gs_println("Bind Storage Buffer: Binding \"%s\" to location %zu, block index: %zu, binding: %zu",
- sbo->name, sbo->location, sbo->block_idx, binding);
- );
- if (sbo->block_idx >= UINT32_MAX) {
- gs_println("Warning: Bind Storage Buffer: Buffer not found: \"%s\"", sbo->name);
- sbo->block_idx = UINT32_MAX - 1;
- }
- }
- if (sbo->block_idx < UINT32_MAX - 1)
- {
- // Not sure what this actually does atm...
- CHECK_GL_CORE(
- // TODO(): This should use 'binding' instead of 'sbo->location'
- glShaderStorageBlockBinding(shader, sbo->block_idx, sbo->location);
- );
- }
- // This is required
- CHECK_GL_CORE(
- // glBindBufferRange(GL_SHADER_STORAGE_BUFFER, binding, sbo->buffer,
- // range_offset, range_size ? range_size : sbo->size - range_offset);
- glBindBufferBase(GL_SHADER_STORAGE_BUFFER, binding, sbo->buffer);
- );
- } break;
- case GS_GRAPHICS_BIND_IMAGE_BUFFER:
- {
- gs_byte_buffer_readc(&cb->commands, uint32_t, tex_slot_id);
- gs_byte_buffer_readc(&cb->commands, uint32_t, binding);
- gs_byte_buffer_readc(&cb->commands, gs_graphics_access_type, access);
- // Grab texture from sampler id
- if (!tex_slot_id || !gs_slot_array_exists(ogl->textures, tex_slot_id)) {
- /*
- gs_timed_action(1000, {
- gs_println("Warning:Bind Image Buffer:Texture %d does not exist.", tex_slot_id);
- });
- */
- continue;
- }
- gsgl_texture_t* tex = gs_slot_array_getp(ogl->textures, tex_slot_id);
- uint32_t gl_access = gsgl_access_type_to_gl_access_type(access);
- uint32_t gl_format = gsgl_texture_format_to_gl_texture_internal_format(tex->desc.format);
- // Bind image texture
- CHECK_GL_CORE(glBindImageTexture(binding, tex->id, 0, GL_FALSE, 0, gl_access, gl_format);)
- } break;
- default: gs_assert(false); break;
- }
- }
- } break;
- case GS_OPENGL_OP_BIND_PIPELINE:
- {
- // Bind pipeline stuff
- gs_byte_buffer_readc(&cb->commands, uint32_t, pipid);
- // Make sure pipeline exists
- if (!pipid || !gs_slot_array_exists(ogl->pipelines, pipid)) {
- /*
- gs_timed_action(1000, {
- gs_println("Warning: Pipeline %d does not exist.", pipid);
- });
- */
- continue;
- }
-
- // Reset cache
- gsgl_reset_data_cache(&ogl->cache);
- // Reset state as well
- gsgl_pipeline_state();
- /* Cache pipeline id */
- ogl->cache.pipeline = gs_handle_create(gs_graphics_pipeline_t, pipid);
- gsgl_pipeline_t* pip = gs_slot_array_getp(ogl->pipelines, pipid);
- /* Compute */
- // Early out if compute, since we're not doing a rasterization stage
- if (pip->compute.shader.id)
- {
- /* Shader */
- if (pip->compute.shader.id && gs_slot_array_exists(ogl->shaders, pip->compute.shader.id)) {
- glUseProgram(gs_slot_array_get(ogl->shaders, pip->compute.shader.id));
- }
- else {
- /*
- gs_timed_action(1000, {
- gs_println("Warning:Opengl:BindPipeline:Compute:Shader %d does not exist.", pip->compute.shader.id);
- });
- */
- }
- continue;
- }
- /* Depth */
- if (!pip->depth.func) {
- // If no depth function (default), then disable
- glDisable(GL_DEPTH_TEST);
- }
- else {
- glEnable(GL_DEPTH_TEST);
- glDepthFunc(gsgl_depth_func_to_gl_depth_func(pip->depth.func));
- }
- glDepthMask(gsgl_depth_mask_to_gl_mask(pip->depth.mask));
- /* Stencil */
- if (!pip->stencil.func) {
- // If no stencil function (default), then disable
- glDisable(GL_STENCIL_TEST);
- } else {
- glEnable(GL_STENCIL_TEST);
- uint32_t func = gsgl_stencil_func_to_gl_stencil_func(pip->stencil.func);
- uint32_t sfail = gsgl_stencil_op_to_gl_stencil_op(pip->stencil.sfail);
- uint32_t dpfail = gsgl_stencil_op_to_gl_stencil_op(pip->stencil.dpfail);
- uint32_t dppass = gsgl_stencil_op_to_gl_stencil_op(pip->stencil.dppass);
- glStencilFunc(func, pip->stencil.ref, pip->stencil.comp_mask);
- glStencilMask(pip->stencil.write_mask);
- glStencilOp(sfail, dpfail, dppass);
- }
- /* Blend */
- if (!pip->blend.func) {
- glDisable(GL_BLEND);
- } else {
- glEnable(GL_BLEND);
- glBlendEquation(gsgl_blend_equation_to_gl_blend_eq(pip->blend.func));
- glBlendFunc(gsgl_blend_mode_to_gl_blend_mode(pip->blend.src, GL_ONE),
- gsgl_blend_mode_to_gl_blend_mode(pip->blend.dst, GL_ZERO));
- }
- /* Raster */
- // Face culling
- if (!pip->raster.face_culling) {
- glDisable(GL_CULL_FACE);
- } else {
- glEnable(GL_CULL_FACE);
- glCullFace(gsgl_cull_face_to_gl_cull_face(pip->raster.face_culling));
- }
- // Winding order
- glFrontFace(gsgl_winding_order_to_gl_winding_order(pip->raster.winding_order));
- /* Shader */
- if (pip->raster.shader.id && gs_slot_array_exists(ogl->shaders, pip->raster.shader.id)) {
- glUseProgram(gs_slot_array_get(ogl->shaders, pip->raster.shader.id));
- }
- else {
- /*
- gs_timed_action(1000, {
- gs_println("Warning:Opengl:BindPipeline:Shader %d does not exist.", pip->raster.shader.id);
- });
- */
- }
- } break;
- case GS_OPENGL_OP_DISPATCH_COMPUTE:
- {
- gs_byte_buffer_readc(&cb->commands, uint32_t, num_x_groups);
- gs_byte_buffer_readc(&cb->commands, uint32_t, num_y_groups);
- gs_byte_buffer_readc(&cb->commands, uint32_t, num_z_groups);
- // Grab currently bound pipeline (TODO(john): assert if this isn't valid)
- if (ogl->cache.pipeline.id == 0 || !gs_slot_array_exists(ogl->pipelines, ogl->cache.pipeline.id)) {
- /*
- gs_timed_action(1000, {
- gs_println("Warning:Opengl:DispatchCompute:Compute Pipeline not bound.");
- });
- */
- continue;
- }
- gsgl_pipeline_t* pip = gs_slot_array_getp(ogl->pipelines, ogl->cache.pipeline.id);
- // If pipeline does not have a compute state bound, then leave
- if (!pip->compute.shader.id) {
- /*
- gs_timed_action(1000, {
- gs_println("Warning:Opengl:DispatchCompute:Compute Pipeline not bound.");
- });
- */
- continue;
- }
- // Dispatch shader
- CHECK_GL_CORE(
- // Memory barrier (TODO(john): make this specifically set in the pipeline state)
- glDispatchCompute(num_x_groups, num_y_groups, num_z_groups);
- glMemoryBarrier(GL_ALL_BARRIER_BITS);
- // glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
- )
- } break;
- case GS_OPENGL_OP_DRAW:
- {
- // Grab currently bound pipeline (TODO(john): assert if this isn't valid)
- gsgl_pipeline_t* pip = gs_slot_array_getp(ogl->pipelines, ogl->cache.pipeline.id);
- // Must have a vertex buffer bound to draw
- if (gs_dyn_array_empty(ogl->cache.vdecls)) {
- gs_timed_action(1000, {
- gs_println("Error:Opengl:Draw: No vertex buffer bound.");
- });
- // gs_assert(false);
- }
- // Keep track whether or not the data is to be instanced
- bool is_instanced = false;
- for (uint32_t i = 0; i < gs_dyn_array_size(pip->layout); ++i)
- {
- // Vertex buffer to bind
- uint32_t vbo_idx = i; //pip->layout[i].buffer_idx;
- gsgl_vertex_buffer_decl_t vdecl = vbo_idx < gs_dyn_array_size(ogl->cache.vdecls) ? ogl->cache.vdecls[vbo_idx] : ogl->cache.vdecls[0];
- gsgl_buffer_t vbo = vdecl.vbo;
- // Manual override. If you manually set divisor/stride/offset, then will not automatically calculate any of those.
- bool is_manual = pip->layout[i].stride | pip->layout[i].divisor | pip->layout[i].offset | (vdecl.data_type == GS_GRAPHICS_VERTEX_DATA_NONINTERLEAVED);
- // Bind buffer
- glBindBuffer(GL_ARRAY_BUFFER, vbo);
- // Stride of vertex attribute
- size_t stride = is_manual ? pip->layout[i].stride :
- gsgl_calculate_vertex_size_in_bytes(pip->layout, gs_dyn_array_size(pip->layout));
- // Byte offset of vertex attribute (if non-interleaved data, then grab offset from decl instead)
- size_t offset = vdecl.data_type == GS_GRAPHICS_VERTEX_DATA_NONINTERLEAVED ? vdecl.offset : is_manual ? pip->layout[i].offset :
- gsgl_get_vertex_attr_byte_offest(pip->layout, i);
- // If there is a vertex divisor for this layout, then we'll draw instanced
- is_instanced |= (pip->layout[i].divisor != 0);
- // Enable the vertex attribute pointer
- glEnableVertexAttribArray(i);
- switch (pip->layout[i].format)
- {
- case GS_GRAPHICS_VERTEX_ATTRIBUTE_FLOAT4: glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, stride, gs_int2voidp(offset)); break;
- case GS_GRAPHICS_VERTEX_ATTRIBUTE_FLOAT3: glVertexAttribPointer(i, 3, GL_FLOAT, GL_FALSE, stride, gs_int2voidp(offset)); break;
- case GS_GRAPHICS_VERTEX_ATTRIBUTE_FLOAT2: glVertexAttribPointer(i, 2, GL_FLOAT, GL_FALSE, stride, gs_int2voidp(offset)); break;
- case GS_GRAPHICS_VERTEX_ATTRIBUTE_FLOAT: glVertexAttribPointer(i, 1, GL_FLOAT, GL_FALSE, stride, gs_int2voidp(offset)); break;
- case GS_GRAPHICS_VERTEX_ATTRIBUTE_UINT4: glVertexAttribIPointer(i, 4, GL_UNSIGNED_INT, stride, gs_int2voidp(offset)); break;
- case GS_GRAPHICS_VERTEX_ATTRIBUTE_UINT3: glVertexAttribIPointer(i, 3, GL_UNSIGNED_INT, stride, gs_int2voidp(offset)); break;
- case GS_GRAPHICS_VERTEX_ATTRIBUTE_UINT2: glVertexAttribIPointer(i, 2, GL_UNSIGNED_INT, stride, gs_int2voidp(offset)); break;
- case GS_GRAPHICS_VERTEX_ATTRIBUTE_UINT: glVertexAttribIPointer(i, 1, GL_UNSIGNED_INT, stride, gs_int2voidp(offset)); break;
- case GS_GRAPHICS_VERTEX_ATTRIBUTE_BYTE: glVertexAttribPointer(i, 1, GL_UNSIGNED_BYTE, GL_TRUE, stride, gs_int2voidp(offset)); break;
- case GS_GRAPHICS_VERTEX_ATTRIBUTE_BYTE2: glVertexAttribPointer(i, 2, GL_UNSIGNED_BYTE, GL_TRUE, stride, gs_int2voidp(offset)); break;
- case GS_GRAPHICS_VERTEX_ATTRIBUTE_BYTE3: glVertexAttribPointer(i, 3, GL_UNSIGNED_BYTE, GL_TRUE, stride, gs_int2voidp(offset)); break;
- case GS_GRAPHICS_VERTEX_ATTRIBUTE_BYTE4: glVertexAttribPointer(i, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, gs_int2voidp(offset)); break;
- // Shouldn't get here
- default: {
- gs_assert(false);
- } break;
- }
- // Set up divisor (for instancing)
- glVertexAttribDivisor(i, pip->layout[i].divisor);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- }
- // Bind all vertex buffers after setting up data and pointers
- for (uint32_t i = 0; i < gs_dyn_array_size(ogl->cache.vdecls); ++i) {
- glBindBuffer(GL_ARRAY_BUFFER, ogl->cache.vdecls[i].vbo);
- }
- // Draw based on bound primitive type in raster
- gs_byte_buffer_readc(&cb->commands, uint32_t, start);
- gs_byte_buffer_readc(&cb->commands, uint32_t, count);
- gs_byte_buffer_readc(&cb->commands, uint32_t, instance_count);
- gs_byte_buffer_readc(&cb->commands, uint32_t, base_vertex);
- gs_byte_buffer_readc(&cb->commands, uint32_t, range_start);
- gs_byte_buffer_readc(&cb->commands, uint32_t, range_end);
- range_end = (range_end && range_end > range_start) ? range_end : start + count;
- // Bind element buffer ranged
- if (ogl->cache.ibo) {
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gs_slot_array_get(ogl->index_buffers, ogl->cache.ibo));
- }
- // If instance count > 1, do instanced drawing
- is_instanced |= (instance_count > 1);
- uint32_t prim = gsgl_primitive_to_gl_primitive(pip->raster.primitive);
- uint32_t itype = gsgl_index_buffer_size_to_gl_index_type(pip->raster.index_buffer_element_size);
- // Draw
- if (ogl->cache.ibo) {
- #ifdef GS_GRAPHICS_IMPL_OPENGL_CORE
- if (is_instanced) glDrawElementsInstancedBaseVertex(prim, count, itype, gs_int2voidp(start), instance_count, base_vertex);
- else glDrawRangeElementsBaseVertex(prim, range_start, range_end, count, itype, gs_int2voidp(start), base_vertex);
- #else
- if (is_instanced) glDrawElementsInstanced(prim, count, itype, gs_int2voidp(start), instance_count);
- else glDrawElements(prim, count, itype, gs_int2voidp(start));
- #endif
- }
- else {
- if (is_instanced) glDrawArraysInstanced(prim, start, count, instance_count);
- else glDrawArrays(prim, start, count);
- }
- } break;
- case GS_OPENGL_OP_REQUEST_TEXTURE_UPDATE:
- {
- gs_byte_buffer_readc(&cb->commands, uint32_t, tex_slot_id);
- gs_byte_buffer_readc(&cb->commands, gs_graphics_texture_desc_t, desc);
- gs_byte_buffer_readc(&cb->commands, size_t, data_size);
- // Update texture with data, depending on update type (for now, just stream new data)
- // Grab texture from sampler id
- if (!tex_slot_id || !gs_slot_array_exists(ogl->textures, tex_slot_id)) {
- gs_timed_action(60, {
- gs_println("Warning:Bind Image Buffer:Texture %d does not exist.", tex_slot_id);
- });
- gs_byte_buffer_advance_position(&cb->commands, data_size);
- }
- gsgl_texture_t* tex = gs_slot_array_getp(ogl->textures, tex_slot_id);
- uint32_t int_format = gsgl_texture_format_to_gl_texture_internal_format(desc.format);
- uint32_t format = gsgl_texture_format_to_gl_texture_format(desc.format);
- uint32_t dt = gsgl_texture_format_to_gl_data_type(desc.format);
- *desc.data = (cb->commands.data + cb->commands.position);
- *tex = gl_texture_update_internal(&desc, tex_slot_id);
- // Bind texture
- // glBindTexture(GL_TEXTURE_2D, tex->id);
- // // Update texture data
- // // glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, desc.width, desc.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (cb->commands.data, cb->commands.position));
- // // glTexImage2D(GL_TEXTURE_2D, 0, int_format, desc.width, desc.height, 0, format, dt, (cb->commands.data, cb->commands.position));
- // glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, desc.width, desc.height, format, dt, (cb->commands.data + cb->commands.position));
- // glBindTexture(GL_TEXTURE_2D, 0);
- gs_byte_buffer_advance_position(&cb->commands, data_size);
- } break;
- case GS_OPENGL_OP_REQUEST_BUFFER_UPDATE:
- {
- gsgl_data_t* ogl = (gsgl_data_t*)gs_subsystem(graphics)->user_data;
- // Read handle id
- gs_byte_buffer_readc(&cb->commands, uint32_t, id);
- // Read type
- gs_byte_buffer_readc(&cb->commands, gs_graphics_buffer_type, type);
- // Read usage
- gs_byte_buffer_readc(&cb->commands, gs_graphics_buffer_usage_type, usage);
- // Read data size
- gs_byte_buffer_readc(&cb->commands, size_t, sz);
- // Read data offset
- gs_byte_buffer_readc(&cb->commands, size_t, offset);
- // Read update type
- gs_byte_buffer_readc(&cb->commands, gs_graphics_buffer_update_type, update_type);
- int32_t glusage = gsgl_buffer_usage_to_gl_enum(usage);
- switch (type)
- {
- // Vertex Buffer
- default:
- case GS_GRAPHICS_BUFFER_VERTEX:
- {
- gsgl_buffer_t buffer = gs_slot_array_get(ogl->vertex_buffers, id);
- glBindBuffer(GL_ARRAY_BUFFER, buffer);
- switch (update_type) {
- case GS_GRAPHICS_BUFFER_UPDATE_SUBDATA: glBufferSubData(GL_ARRAY_BUFFER, offset, sz, (cb->commands.data + cb->commands.position)); break;
- default: glBufferData(GL_ARRAY_BUFFER, sz, (cb->commands.data + cb->commands.position), glusage); break;
- }
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- } break;
- case GS_GRAPHICS_BUFFER_INDEX:
- {
- gsgl_buffer_t buffer = gs_slot_array_get(ogl->index_buffers, id);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
- switch (update_type) {
- case GS_GRAPHICS_BUFFER_UPDATE_SUBDATA: glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, sz, (cb->commands.data + cb->commands.position)); break;
- default: glBufferData(GL_ELEMENT_ARRAY_BUFFER, sz, (cb->commands.data + cb->commands.position), glusage); break;
- }
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- } break;
- case GS_GRAPHICS_BUFFER_UNIFORM:
- {
- // Have to
- gsgl_uniform_buffer_t* u = gs_slot_array_getp(ogl->uniform_buffers, id);
- glBindBuffer(GL_UNIFORM_BUFFER, u->ubo);
- switch (update_type) {
- case GS_GRAPHICS_BUFFER_UPDATE_SUBDATA: {
- glBufferSubData(GL_UNIFORM_BUFFER, offset, sz, (cb->commands.data + cb->commands.position));
- } break;
- default: {
- // Reset uniform size
- u->size = sz;
- // Recreate buffer
- glBufferData(GL_UNIFORM_BUFFER, sz, (cb->commands.data + cb->commands.position), glusage);
- } break;
- }
- glBindBuffer(GL_UNIFORM_BUFFER, 0);
- } break;
- case GS_GRAPHICS_BUFFER_SHADER_STORAGE:
- {
- gs_graphics_storage_buffer_desc_t desc = {
- .data = cb->commands.data + cb->commands.position,
- .size = sz,
- .usage = usage,
- .update = {
- .type = update_type,
- .offset = offset,
- },
- };
- gs_handle(gs_graphics_storage_buffer_t) hndl;
- hndl.id = id;
- gs_graphics_storage_buffer_update(hndl, &desc);
- } break;
- }
- // Advance past data
- gs_byte_buffer_advance_position(&cb->commands, sz);
- } break;
- default:
- {
- // Op code not supported yet!
- gs_println("Op code not supported yet: %zu", (uint32_t)op_code);
- gs_assert(false);
- }
- }
- }
-
- // Clear byte buffer of commands
- gs_byte_buffer_clear(&cb->commands);
- // Set num commands to 0
- cb->num_commands = 0;
- }
- GS_API_DECL void
- gs_graphics_init(gs_graphics_t* graphics)
- {
- // Push back 0 handles into slot arrays (for 0 init validation)
- gsgl_data_t* ogl = (gsgl_data_t*)graphics->user_data;
- gs_slot_array_insert(ogl->shaders, 0);
- gs_slot_array_insert(ogl->vertex_buffers, 0);
- gs_slot_array_insert(ogl->index_buffers, 0);
- gs_slot_array_insert(ogl->frame_buffers, 0);
- gsgl_uniform_list_t ul = gs_default_val();
- gsgl_uniform_buffer_t ub = gs_default_val();
- gsgl_pipeline_t pip = gs_default_val();
- gsgl_renderpass_t rp = gs_default_val();
- gsgl_texture_t tex = gs_default_val();
- gsgl_storage_buffer_t sb = gs_default_val();
- gs_slot_array_insert(ogl->uniforms, ul);
- gs_slot_array_insert(ogl->pipelines, pip);
- gs_slot_array_insert(ogl->renderpasses, rp);
- gs_slot_array_insert(ogl->uniform_buffers, ub);
- gs_slot_array_insert(ogl->textures, tex);
- gs_slot_array_insert(ogl->storage_buffers, sb);
- // Construct vao then bind
- glGenVertexArrays(1, &ogl->cache.vao);
- glBindVertexArray(ogl->cache.vao);
- // Reset data cache for rendering ops
- gsgl_reset_data_cache(&ogl->cache);
- // Init info object
- gs_graphics_info_t* info = &gs_subsystem(graphics)->info;
- // Major/Minor version
- glGetIntegerv(GL_MAJOR_VERSION, (GLint*)&info->major_version);
- glGetIntegerv(GL_MINOR_VERSION, (GLint*)&info->minor_version);
- // Max texture units
- glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, (GLint*)&info->max_texture_units);
- // Compute shader info
- CHECK_GL_CORE(
- info->compute.available = info->major_version >= 4 && info->minor_version >= 3;
- if (info->compute.available) {
- // Work group counts
- glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, (int32_t*)&info->compute.max_work_group_count[0]);
- glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, (int32_t*)&info->compute.max_work_group_count[1]);
- glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, (int32_t*)&info->compute.max_work_group_count[2]);
- // Work group sizes
- glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, (int32_t*)&info->compute.max_work_group_size[0]);
- glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1, (int32_t*)&info->compute.max_work_group_size[1]);
- glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2, (int32_t*)&info->compute.max_work_group_size[2]);
- // Work group invocations
- glGetIntegerv(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS, (int32_t*)&info->compute.max_work_group_invocations);
- }
- glGetIntegerv(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, (int32_t*)&info->max_ssbo_block_size);
- )
- const GLubyte* glslv = glGetString(GL_SHADING_LANGUAGE_VERSION);
- gs_println("GLSL Version: %s", glslv);
- // Set up all function pointers for graphics context
- // Create
- graphics->api.texture_create = gs_graphics_texture_create_impl;
- graphics->api.uniform_create = gs_graphics_uniform_create_impl;
- graphics->api.shader_create = gs_graphics_shader_create_impl;
- graphics->api.vertex_buffer_create = gs_graphics_vertex_buffer_create_impl;
- graphics->api.index_buffer_create = gs_graphics_index_buffer_create_impl;
- graphics->api.uniform_buffer_create = gs_graphics_uniform_buffer_create_impl;
- graphics->api.storage_buffer_create = gs_graphics_storage_buffer_create_impl;
- graphics->api.framebuffer_create = gs_graphics_framebuffer_create_impl;
- graphics->api.renderpass_create = gs_graphics_renderpass_create_impl;
- graphics->api.pipeline_create = gs_graphics_pipeline_create_impl;
- // Destroy
- graphics->api.texture_destroy = gs_graphics_texture_destroy_impl;
- graphics->api.uniform_destroy = gs_graphics_uniform_destroy_impl;
- graphics->api.shader_destroy = gs_graphics_shader_destroy_impl;
- graphics->api.vertex_buffer_destroy = gs_graphics_vertex_buffer_destroy_impl;
- graphics->api.index_buffer_destroy = gs_graphics_index_buffer_destroy_impl;
- graphics->api.uniform_buffer_destroy = gs_graphics_uniform_buffer_destroy_impl;
- graphics->api.storage_buffer_destroy = gs_graphics_storage_buffer_destroy_impl;
- graphics->api.framebuffer_destroy = gs_graphics_framebuffer_destroy_impl;
- graphics->api.renderpass_destroy = gs_graphics_renderpass_destroy_impl;
- graphics->api.pipeline_destroy = gs_graphics_pipeline_destroy_impl;
- // Resource Updates (main thread only)
- graphics->api.vertex_buffer_update = gs_graphics_vertex_buffer_update_impl;
- graphics->api.index_buffer_update = gs_graphics_index_buffer_update_impl;
- graphics->api.storage_buffer_update = gs_graphics_storage_buffer_update_impl;
- graphics->api.texture_update = gs_graphics_texture_update_impl;
- graphics->api.texture_read = gs_graphics_texture_read_impl;
- // Util
- graphics->api.storage_buffer_map_get = gs_graphics_storage_buffer_map_get_impl;
- graphics->api.storage_buffer_lock = gs_grapics_storage_buffer_lock_impl;
- graphics->api.storage_buffer_unlock = gs_grapics_storage_buffer_unlock_impl;
- graphics->api.storage_buffer_get_data = gs_storage_buffer_get_data_impl;
- // Submission (Main Thread)
- graphics->api.command_buffer_submit = gs_graphics_command_buffer_submit_impl;
- // Enable debug output
- glEnable(GL_DEBUG_OUTPUT);
- // glDebugMessageCallback(gsgl_message_cb, 0);
- }
- #endif // GS_GRAPHICS_IMPL_OPENGL
- #endif // GS_GRAPHICS_IMPL_H
|