opengl.c (34755B)
1 ////////////////////////////////////////////////////////////////// 2 // opengl.c 3 4 #define ogl_safe_set(ptr, hndl_arg) ((ptr) ? ((ptr)->hndl_arg.u) : (0)) 5 6 RV_INTERNAL GLenum rv_usage_to_gl(rv_buffer_usage_t usage) { 7 GLenum mode = GL_STATIC_DRAW; 8 switch (usage) { 9 default: rv_unreachable(); 10 case RV_BUFFER_USAGE_STATIC: mode = GL_STATIC_DRAW; break; 11 case RV_BUFFER_USAGE_DYNAMIC: mode = GL_DYNAMIC_DRAW; break; 12 case RV_BUFFER_USAGE_STREAM: mode = GL_STREAM_DRAW; break; 13 } 14 return mode; 15 } 16 17 RV_INTERNAL GLenum rv_shader_to_gl(rv_shader_type_t type) { 18 GLenum mode = 0; 19 switch (type) { 20 default: rv_unreachable(); 21 case RV_SHADER_TYPE_VERTEX: mode = GL_VERTEX_SHADER; break; 22 case RV_SHADER_TYPE_FRAGMENT: mode = GL_FRAGMENT_SHADER; break; 23 } 24 return mode; 25 } 26 27 RV_INTERNAL GLenum rv_primitive_to_gl(rv_primitive_type_t type) { 28 GLenum res = 0; 29 switch (type) { 30 default: rv_unreachable(); 31 case RV_PRIMITIVE_TYPE_TRIANGLES: res = GL_TRIANGLES; break; 32 } 33 return res; 34 } 35 36 RV_INTERNAL s64 rv_vattr_type_size(rv_vattr_type_t type) { 37 s64 size = 0; 38 switch (type) { 39 case RV_VATTR_TYPE_FLOAT4: { size = sizeof(f32) * 4; } break; 40 case RV_VATTR_TYPE_FLOAT3: { size = sizeof(f32) * 3; } break; 41 case RV_VATTR_TYPE_FLOAT2: { size = sizeof(f32) * 2; } break; 42 case RV_VATTR_TYPE_FLOAT: { size = sizeof(f32) * 1; } break; 43 case RV_VATTR_TYPE_UINT4: { size = sizeof(u32) * 4; } break; 44 case RV_VATTR_TYPE_UINT3: { size = sizeof(u32) * 3; } break; 45 case RV_VATTR_TYPE_UINT2: { size = sizeof(u32) * 2; } break; 46 case RV_VATTR_TYPE_UINT: { size = sizeof(u32) * 1; } break; 47 case RV_VATTR_TYPE_BYTE4: { size = sizeof(u8 ) * 4; } break; 48 case RV_VATTR_TYPE_BYTE3: { size = sizeof(u8 ) * 3; } break; 49 case RV_VATTR_TYPE_BYTE2: { size = sizeof(u8 ) * 2; } break; 50 case RV_VATTR_TYPE_BYTE: { size = sizeof(u8 ) * 1; } break; 51 } 52 return size; 53 } 54 55 56 RV_INTERNAL GLenum rv_tex_wrap_to_gl(rv_texture_wrap_t type) { 57 GLenum wrap = GL_REPEAT; 58 switch (type) { 59 default: rv_unreachable(); 60 case RV_TEXTURE_WRAP_REPEAT: wrap = GL_REPEAT; break; 61 case RV_TEXTURE_WRAP_MIRRORED_REPEAT: wrap = GL_MIRRORED_REPEAT; break; 62 case RV_TEXTURE_WRAP_CLAMP_TO_EDGE: wrap = GL_CLAMP_TO_EDGE; break; 63 }; 64 65 return wrap; 66 } 67 68 69 GLenum rv_blend_equation_to_gl(rv_blend_equation_t eq) 70 { 71 GLenum beq = GL_FUNC_ADD; 72 switch (eq) { 73 default: rv_unreachable(); 74 case RV_BLEND_EQUATION_ADD: beq = GL_FUNC_ADD; break; 75 case RV_BLEND_EQUATION_SUBTRACT: beq = GL_FUNC_SUBTRACT; break; 76 case RV_BLEND_EQUATION_REVERSE_SUBTRACT: beq = GL_FUNC_REVERSE_SUBTRACT; break; 77 case RV_BLEND_EQUATION_MIN: beq = GL_MIN; break; 78 case RV_BLEND_EQUATION_MAX: beq = GL_MAX; break; 79 }; 80 81 return beq; 82 } 83 84 GLenum rv_blend_mode_to_gl(rv_blend_mode_t type, GLenum def) 85 { 86 GLenum mode = def; 87 switch (type) { 88 default: rv_unreachable(); 89 case RV_BLEND_MODE_DEFAULT: mode = def; break; 90 case RV_BLEND_MODE_ZERO: mode = GL_ZERO; break; 91 case RV_BLEND_MODE_ONE: mode = GL_ONE; break; 92 case RV_BLEND_MODE_SRC_COLOR: mode = GL_SRC_COLOR; break; 93 case RV_BLEND_MODE_ONE_MINUS_SRC_COLOR: mode = GL_ONE_MINUS_SRC_COLOR; break; 94 case RV_BLEND_MODE_DST_COLOR: mode = GL_DST_COLOR; break; 95 case RV_BLEND_MODE_ONE_MINUS_DST_COLOR: mode = GL_ONE_MINUS_DST_COLOR; break; 96 case RV_BLEND_MODE_SRC_ALPHA: mode = GL_SRC_ALPHA; break; 97 case RV_BLEND_MODE_ONE_MINUS_SRC_ALPHA: mode = GL_ONE_MINUS_SRC_ALPHA; break; 98 case RV_BLEND_MODE_DST_ALPHA: mode = GL_DST_ALPHA; break; 99 case RV_BLEND_MODE_ONE_MINUS_DST_ALPHA: mode = GL_ONE_MINUS_DST_ALPHA; break; 100 case RV_BLEND_MODE_CONSTANT_COLOR: mode = GL_CONSTANT_COLOR; break; 101 case RV_BLEND_MODE_ONE_MINUS_CONSTANT_COLOR: mode = GL_ONE_MINUS_CONSTANT_COLOR; break; 102 case RV_BLEND_MODE_CONSTANT_ALPHA: mode = GL_CONSTANT_ALPHA; break; 103 case RV_BLEND_MODE_ONE_MINUS_CONSTANT_ALPHA: mode = GL_ONE_MINUS_CONSTANT_ALPHA; break; 104 } 105 return mode; 106 } 107 108 RV_INTERNAL struct { 109 GLuint vao; 110 bool32 is_init; 111 112 rv_texture_t default_tex; 113 114 rv_ibo_t* bound_ibo; 115 rv_pipeline_t* bound_pip; 116 rv_framebuffer_t* bound_fbuf; 117 } ogl_ctx; 118 119 void ogl_bind_fbuf(rv_framebuffer_t* fbuf) { 120 ogl_ctx.bound_fbuf = fbuf; 121 glBindFramebuffer(GL_FRAMEBUFFER, ogl_safe_set(fbuf, handle)); 122 if (fbuf) { 123 s32 r = 0; 124 for (rv_texture_node_t* c = fbuf->color_attachement_first; c; c = c->next, r++) { 125 if (c->tex) { 126 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + r, GL_TEXTURE_2D, c->tex->handle.u, 0); 127 } else { 128 rv_unreachable(); 129 } 130 } 131 } 132 } 133 134 135 RV_INTERNAL void ogl_handle_command(rv_command_t* c); 136 137 RV_GLOBAL void rv_window_render_commit(rv_window_handle_t* window, rv_render_pass_list_t* passes) 138 { 139 rv_window_render_begin(window); 140 141 rv_temp_arena scratch = rv_scratch_begin(0, 0); 142 143 rv_render_pass_t* initial_rpass = passes->first; 144 145 if (!ogl_ctx.is_init) { 146 ogl_ctx.is_init = true; 147 148 glGenVertexArrays(1, &ogl_ctx.vao); 149 glBindVertexArray(ogl_ctx.vao); 150 151 152 153 rv_render_pass_t* extra_initial_rpass = rv_push(scratch.arena, rv_render_pass_t); 154 extra_initial_rpass->next = initial_rpass; 155 initial_rpass = extra_initial_rpass; 156 157 ogl_ctx.default_tex = (rv_texture_t){}; 158 rv_get_default_texture(&ogl_ctx.default_tex.data, &ogl_ctx.default_tex.size); 159 rv_cmd_push_obj(scratch.arena, &extra_initial_rpass->commands, RV_COMMAND_OBJ_TEXTURE, RV_RENDER_OBJ_OP_CREATE, &ogl_ctx.default_tex); 160 } 161 162 163 for (rv_render_pass_t* p = initial_rpass; p; p = p->next) { 164 { // unbind everything 165 166 if (ogl_ctx.bound_ibo) { 167 ogl_ctx.bound_ibo = NULL; 168 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 169 } 170 171 if (ogl_ctx.bound_pip) { 172 ogl_ctx.bound_pip = NULL; 173 glUseProgram(0); 174 } 175 176 if (ogl_ctx.bound_fbuf || p->framebuffer) { 177 ogl_bind_fbuf(p->framebuffer); 178 } 179 } 180 181 for (rv_command_t* c = p->commands.first; c; c = c->next) { 182 ogl_handle_command(c); 183 } 184 } 185 186 rv_scratch_end(scratch); 187 188 rv_window_render_end(window); 189 } 190 191 RV_INTERNAL void ogl_handle_command(rv_command_t* c) { 192 switch (c->type) { 193 case RV_COMMAND_INVALID: { 194 rv_unreachable(); 195 } break; 196 197 case RV_COMMAND_CUSTOM: { 198 rv_assert(c->custom.func); 199 if (c->custom.func) { 200 c->custom.func(c->custom.data); 201 } 202 } break; 203 204 case RV_COMMAND_COMMAND_LIST: { 205 for (rv_command_t* cc = c->command_list.first; cc; cc = cc->next) { 206 ogl_handle_command(cc); 207 } 208 } break; 209 210 case RV_COMMAND_CLEAR: { 211 for (rv_render_clear_desc_t* clear = c->clear.first; clear; clear = clear->next) { 212 if (clear->flags == RV_RENDER_CLEAR_FLAG_NONE) continue; 213 214 int opengl_clear_mask = 0; 215 if (clear->flags & RV_RENDER_CLEAR_FLAG_COLOR) { 216 glClearColor(clear->color[0], clear->color[1], clear->color[2], clear->color[3]); 217 opengl_clear_mask |= GL_COLOR_BUFFER_BIT; 218 } 219 if (clear->flags & RV_RENDER_CLEAR_FLAG_DEPTH) opengl_clear_mask |= GL_DEPTH_BUFFER_BIT; 220 if (clear->flags & RV_RENDER_CLEAR_FLAG_STENCIL) opengl_clear_mask |= GL_STENCIL_BUFFER_BIT; 221 222 glClear(opengl_clear_mask); 223 } 224 } break; 225 226 case RV_COMMAND_SET_VIEWPORT: { 227 glViewport(c->viewport.x, c->viewport.y, c->viewport.z, c->viewport.w); 228 } break; 229 230 case RV_COMMAND_OBJ_VERTEX: { 231 rv_vbo_t* vbo = c->obj.vbo; 232 switch (c->obj.operation) { 233 case RV_RENDER_OBJ_OP_CREATE: { 234 rv_assert(!ogl_ctx.bound_pip); 235 236 glGenBuffers(1, &vbo->handle.u); 237 glBindBuffer(GL_ARRAY_BUFFER, vbo->handle.u); 238 glBufferData(GL_ARRAY_BUFFER, vbo->size, vbo->data, rv_usage_to_gl(vbo->usage)); 239 glBindBuffer(GL_ARRAY_BUFFER, 0); 240 } break; 241 242 case RV_RENDER_OBJ_OP_UPDATE: { 243 rv_assert(!ogl_ctx.bound_pip); 244 245 glBindBuffer(GL_ARRAY_BUFFER, vbo->handle.u); 246 glBufferData(GL_ARRAY_BUFFER, c->obj.vbo_update.size, c->obj.vbo_update.data, rv_usage_to_gl(vbo->usage)); 247 glBindBuffer(GL_ARRAY_BUFFER, 0); 248 } break; 249 250 case RV_RENDER_OBJ_OP_BIND: { 251 if (ogl_ctx.bound_pip) { 252 s32 bind_index = c->obj.vbo_bind.bind_index; 253 s32 base_offset = c->obj.vbo_bind.base_offset; 254 rv_vattr_bind_t* vattr_bind_override_list = c->obj.vbo_bind.vattr_override_first; 255 glBindBuffer(GL_ARRAY_BUFFER, vbo->handle.u); 256 257 // set vattrs 258 s32 auto_stride = 0; 259 for (rv_vattr_t* v = ogl_ctx.bound_pip->vattr_first; v; v = v->next) { 260 if (v->bind_index == bind_index) { 261 bool32 found_override = false; 262 for (rv_vattr_bind_t* vo = vattr_bind_override_list; vo; vo = vo->next) { 263 if (vo->desc == v) { 264 found_override = true; 265 break; 266 } 267 } 268 if (!found_override) 269 auto_stride += rv_vattr_type_size(v->type); 270 } 271 } 272 s32 auto_offset = 0; 273 s32 i = 0; 274 for (rv_vattr_t* v = ogl_ctx.bound_pip->vattr_first; v; v = v->next, i++) { 275 if (v->bind_index == bind_index) { 276 glEnableVertexAttribArray(i); 277 s32 offset = auto_offset; 278 s32 stride = auto_stride; 279 s32 divisor = v->divisor; 280 bool32 found_override = false; 281 for (rv_vattr_bind_t* vo = vattr_bind_override_list; vo; vo = vo->next) { 282 if (vo->desc == v) { 283 offset = vo->offset; 284 stride = vo->stride; 285 divisor = vo->divisor; 286 break; 287 } 288 } 289 switch (v->type) { 290 case RV_VATTR_TYPE_FLOAT4: glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, stride, (void*)(s64)(base_offset + offset)); break; 291 case RV_VATTR_TYPE_FLOAT3: glVertexAttribPointer(i, 3, GL_FLOAT, GL_FALSE, stride, (void*)(s64)(base_offset + offset)); break; 292 case RV_VATTR_TYPE_FLOAT2: glVertexAttribPointer(i, 2, GL_FLOAT, GL_FALSE, stride, (void*)(s64)(base_offset + offset)); break; 293 case RV_VATTR_TYPE_FLOAT: glVertexAttribPointer(i, 1, GL_FLOAT, GL_FALSE, stride, (void*)(s64)(base_offset + offset)); break; 294 case RV_VATTR_TYPE_UINT4: glVertexAttribIPointer(i, 4, GL_UNSIGNED_INT, stride, (void*)(s64)(base_offset + offset)); break; 295 case RV_VATTR_TYPE_UINT3: glVertexAttribIPointer(i, 3, GL_UNSIGNED_INT, stride, (void*)(s64)(base_offset + offset)); break; 296 case RV_VATTR_TYPE_UINT2: glVertexAttribIPointer(i, 2, GL_UNSIGNED_INT, stride, (void*)(s64)(base_offset + offset)); break; 297 case RV_VATTR_TYPE_UINT: glVertexAttribIPointer(i, 1, GL_UNSIGNED_INT, stride, (void*)(s64)(base_offset + offset)); break; 298 case RV_VATTR_TYPE_BYTE: glVertexAttribPointer(i, 1, GL_UNSIGNED_BYTE, GL_TRUE, stride, (void*)(s64)(base_offset + offset)); break; 299 case RV_VATTR_TYPE_BYTE2: glVertexAttribPointer(i, 2, GL_UNSIGNED_BYTE, GL_TRUE, stride, (void*)(s64)(base_offset + offset)); break; 300 case RV_VATTR_TYPE_BYTE3: glVertexAttribPointer(i, 3, GL_UNSIGNED_BYTE, GL_TRUE, stride, (void*)(s64)(base_offset + offset)); break; 301 case RV_VATTR_TYPE_BYTE4: glVertexAttribPointer(i, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, (void*)(s64)(base_offset + offset)); break; 302 default: rv_unreachable(); break; 303 } 304 if (!found_override) 305 auto_offset += rv_vattr_type_size(v->type); 306 if (v->divisor) { 307 glVertexAttribDivisor(i, v->divisor); 308 } 309 } 310 } 311 } else { 312 rv_unreachable(); 313 } 314 } break; 315 316 case RV_RENDER_OBJ_OP_DESTROY: { 317 rv_assert(!ogl_ctx.bound_pip); 318 319 glDeleteBuffers(1, &vbo->handle.u); 320 vbo->handle.u = 0; 321 } break; 322 } 323 } break; 324 325 case RV_COMMAND_OBJ_INDEX: { 326 rv_ibo_t* ibo = c->obj.ibo; 327 switch (c->obj.operation) { 328 case RV_RENDER_OBJ_OP_CREATE: { 329 rv_assert(!ogl_ctx.bound_pip); 330 331 glGenBuffers(1, &ibo->handle.u); 332 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo->handle.u); 333 glBufferData(GL_ELEMENT_ARRAY_BUFFER, ibo->size, ibo->data, rv_usage_to_gl(ibo->usage)); 334 335 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ogl_safe_set(ogl_ctx.bound_ibo, handle)); 336 } break; 337 338 case RV_RENDER_OBJ_OP_UPDATE: { 339 rv_assert(!ogl_ctx.bound_pip); 340 341 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo->handle.u); 342 glBufferData(GL_ELEMENT_ARRAY_BUFFER, c->obj.ibo_update.size, c->obj.ibo_update.data, rv_usage_to_gl(ibo->usage)); 343 344 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ogl_safe_set(ogl_ctx.bound_ibo, handle)); 345 } break; 346 347 case RV_RENDER_OBJ_OP_BIND: { 348 ogl_ctx.bound_ibo = ibo; 349 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ogl_safe_set(ogl_ctx.bound_ibo, handle)); 350 } break; 351 352 case RV_RENDER_OBJ_OP_DESTROY: { 353 rv_assert(!ogl_ctx.bound_pip); 354 355 glDeleteBuffers(1, &ibo->handle.u); 356 ibo->handle.u = 0; 357 if (ogl_ctx.bound_ibo == ibo) { 358 ogl_ctx.bound_ibo = NULL; 359 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 360 } 361 } break; 362 } 363 } break; 364 365 case RV_COMMAND_OBJ_SHADER: { 366 rv_shader_t* shader = c->obj.shader; 367 switch (c->obj.operation) { 368 case RV_RENDER_OBJ_OP_CREATE: { 369 shader->handle.u = glCreateShader(rv_shader_to_gl(shader->type)); 370 glShaderSource(shader->handle.u, 1, (const char* const*)&shader->source.str, (s32*)&shader->source.len); 371 glCompileShader(shader->handle.u); 372 373 { // check for errors 374 int shader_compile_success; 375 glGetShaderiv(shader->handle.u, GL_COMPILE_STATUS, &shader_compile_success); 376 377 if (!shader_compile_success) { 378 char info_log[512]; 379 glGetShaderInfoLog(shader->handle.u, 512, NULL, info_log); 380 fprintf(stderr, "-------------ERROR------------\n" 381 "::OpenGL Failed to compile shader::\n%s\n", info_log); 382 fprintf(stderr, "-------------SOURCE------------\n"); 383 fprintf(stderr, "%.*s\n", rv_s8v(shader->source)); 384 fprintf(stderr, "\n------------END_SOURCE----------\n"); 385 rv_assert(shader_compile_success); 386 } 387 } 388 } break; 389 390 case RV_RENDER_OBJ_OP_UPDATE: { 391 rv_unreachable(); 392 } break; 393 394 case RV_RENDER_OBJ_OP_BIND: { 395 rv_unreachable(); 396 } break; 397 398 case RV_RENDER_OBJ_OP_DESTROY: { 399 glDeleteShader(shader->handle.u); 400 shader->handle.u = 0; 401 } break; 402 } 403 } break; 404 405 case RV_COMMAND_OBJ_PIPELINE: { 406 rv_pipeline_t* pipeline = c->obj.pipeline; 407 switch (c->obj.operation) { 408 case RV_RENDER_OBJ_OP_CREATE: { 409 pipeline->handle.u = glCreateProgram(); 410 for (rv_shader_node_t* s = pipeline->shader_first; s; s = s->next) { 411 glAttachShader(pipeline->handle.u, s->shader->handle.u); 412 } 413 glLinkProgram(pipeline->handle.u); 414 415 { 416 int program_link_success; 417 glGetProgramiv(pipeline->handle.u, GL_LINK_STATUS, &program_link_success); 418 419 if (!program_link_success) { 420 char info_log[512]; 421 glGetProgramInfoLog(pipeline->handle.u, 512, NULL, info_log); 422 fprintf(stderr, "-------------ERROR------------\n" 423 "::OpenGL Failed to link shader program::\n%s\n", info_log); 424 rv_assert(program_link_success); 425 } 426 } 427 428 // find uniform locations 429 for (rv_uniform_t* u = pipeline->uniform_desc_first; u; u = u->next) { 430 u->pipeline_uniform_handle.u = glGetUniformLocation(pipeline->handle.u, (const char*)u->name_null_terminated.str); 431 } 432 433 glUseProgram(pipeline->handle.u); 434 435 // set up sampler channels 436 s32 sampler_channel = 0; 437 for (rv_uniform_t* u = pipeline->uniform_desc_first; u; u = u->next) { 438 if (u->type == RV_UNIFORM_TEX) { 439 glUniform1i(u->pipeline_uniform_handle.u, sampler_channel); 440 sampler_channel++; 441 } 442 } 443 // turn back to previous state 444 glUseProgram(ogl_safe_set(ogl_ctx.bound_pip, handle)); 445 } break; 446 447 case RV_RENDER_OBJ_OP_UPDATE: { 448 rv_unreachable(); 449 } break; 450 451 case RV_RENDER_OBJ_OP_BIND: { 452 ogl_ctx.bound_pip = pipeline; 453 if (pipeline) { 454 glUseProgram(pipeline->handle.u); 455 456 if (pipeline->disable_blend) { 457 glDisable(GL_BLEND); 458 } else { 459 glEnable(GL_BLEND); 460 glBlendEquation(rv_blend_equation_to_gl(pipeline->blend_equation)); 461 glBlendFunc(rv_blend_mode_to_gl(pipeline->blend_src, GL_SRC_ALPHA), rv_blend_mode_to_gl(pipeline->blend_dst, GL_ONE_MINUS_SRC_ALPHA)); 462 } 463 464 // activate textures and sample2d, if any 465 s32 sampler_channel = 0; 466 for (rv_uniform_t* u = pipeline->uniform_desc_first; u; u = u->next) { 467 if (u->type == RV_UNIFORM_TEX) { 468 bool32 has_queued_update = false; 469 { 470 for (rv_command_t* c_future = c->next; c_future; c_future = c_future->next) { 471 if (c_future->type == RV_COMMAND_DRAW || c_future->type == RV_COMMAND_OBJ_PIPELINE) { 472 // reached end... 473 break; 474 } 475 if (c_future->type == RV_COMMAND_UNIFORM_UPDATE) { 476 if (c_future->uniform_update.desc == u) { 477 // found something that updates this uniform 478 has_queued_update = true; 479 break; 480 } 481 } 482 } 483 } 484 if (!has_queued_update) { 485 glActiveTexture(GL_TEXTURE0 + sampler_channel); 486 if (u->last_val.v_tex) { 487 glBindTexture(GL_TEXTURE_2D, u->last_val.v_tex->handle.u); 488 } else { 489 glBindTexture(GL_TEXTURE_2D, ogl_ctx.default_tex.handle.u); 490 } 491 } 492 sampler_channel++; 493 } 494 } 495 } else { 496 glUseProgram(0); 497 } 498 } break; 499 500 case RV_RENDER_OBJ_OP_DESTROY: { 501 glDeleteProgram(pipeline->handle.u); 502 pipeline->handle.u = 0; 503 for (rv_uniform_t* u = pipeline->uniform_desc_first; u; u = u->next) { 504 u->pipeline_uniform_handle.u = 0; 505 } 506 if (ogl_ctx.bound_pip == pipeline) { 507 ogl_ctx.bound_pip = NULL; 508 glUseProgram(0); 509 } 510 } break; 511 } 512 } break; 513 514 case RV_COMMAND_OBJ_TEXTURE: { 515 rv_texture_t* tex = c->obj.tex; 516 switch (c->obj.operation) { 517 case RV_RENDER_OBJ_OP_CREATE: { 518 glGenTextures(1, &tex->handle.u); 519 520 s32 sampler_channel = 0; 521 if (ogl_ctx.bound_pip) { 522 // need to update the existing bound sampler 523 // ... or make sure we don't override a bound one 524 for (rv_uniform_t* u = ogl_ctx.bound_pip->uniform_desc_first; u; u = u->next) { 525 if (u->type == RV_UNIFORM_TEX) { 526 if (u->last_val.v_tex == tex) { 527 // found our texture 528 break; 529 } 530 sampler_channel++; 531 } 532 } 533 } 534 glActiveTexture(GL_TEXTURE0 + sampler_channel); 535 glBindTexture(GL_TEXTURE_2D, tex->handle.u); 536 537 switch(tex->format) 538 { 539 case RV_TEXTURE_FORMAT_A8: glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, tex->size.x, tex->size.y, 0, GL_ALPHA, GL_UNSIGNED_BYTE, tex->data); break; 540 case RV_TEXTURE_FORMAT_R8: glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, tex->size.x, tex->size.y, 0, GL_RED, GL_UNSIGNED_BYTE, tex->data); break; 541 case RV_TEXTURE_FORMAT_RGB8: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, tex->size.x, tex->size.y, 0, GL_RGB, GL_UNSIGNED_BYTE, tex->data); break; 542 case RV_TEXTURE_FORMAT_RGBA8: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex->size.x, tex->size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex->data); break; 543 case RV_TEXTURE_FORMAT_RGBA16F: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, tex->size.x, tex->size.y, 0, GL_RGBA, GL_FLOAT, tex->data); break; 544 case RV_TEXTURE_FORMAT_RGBA32F: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, tex->size.x, tex->size.y, 0, GL_RGBA, GL_FLOAT, tex->data); break; 545 case RV_TEXTURE_FORMAT_DEPTH8: glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, tex->size.x, tex->size.y, 0, GL_DEPTH_COMPONENT, GL_FLOAT, tex->data); break; 546 case RV_TEXTURE_FORMAT_DEPTH16: glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, tex->size.x, tex->size.y, 0, GL_DEPTH_COMPONENT, GL_FLOAT, tex->data); break; 547 case RV_TEXTURE_FORMAT_DEPTH24: glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, tex->size.x, tex->size.y, 0, GL_DEPTH_COMPONENT, GL_FLOAT, tex->data); break; 548 case RV_TEXTURE_FORMAT_DEPTH32F: glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, tex->size.x, tex->size.y, 0, GL_DEPTH_COMPONENT, GL_FLOAT, tex->data); break; 549 case RV_TEXTURE_FORMAT_DEPTH24_STENCIL8: glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, tex->size.x, tex->size.y, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, tex->data); break; 550 case RV_TEXTURE_FORMAT_DEPTH32F_STENCIL8: glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH32F_STENCIL8, tex->size.x, tex->size.y, 0, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, tex->data); break; 551 default: rv_unreachable(); break; 552 } 553 554 GLenum mag_filter = tex->mag_filter == RV_TEXTURE_FILTER_NEAREST ? GL_NEAREST : GL_LINEAR; 555 GLenum min_filter = tex->min_filter == RV_TEXTURE_FILTER_NEAREST ? GL_NEAREST : GL_LINEAR; 556 557 if (tex->num_mips) { 558 if (tex->min_filter == RV_TEXTURE_FILTER_NEAREST) { 559 min_filter = tex->mip_filter == RV_TEXTURE_FILTER_NEAREST ? GL_NEAREST_MIPMAP_NEAREST : 560 GL_NEAREST_MIPMAP_LINEAR; 561 } 562 else { 563 min_filter = tex->mip_filter == RV_TEXTURE_FILTER_NEAREST ? GL_LINEAR_MIPMAP_NEAREST : 564 GL_NEAREST_MIPMAP_LINEAR; 565 } 566 } 567 568 GLenum texture_wrap_s = rv_tex_wrap_to_gl(tex->wrap_s); 569 GLenum texture_wrap_t = rv_tex_wrap_to_gl(tex->wrap_t); 570 571 if (tex->num_mips) { 572 glGenerateMipmap(GL_TEXTURE_2D); 573 } 574 575 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, texture_wrap_s); 576 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, texture_wrap_t); 577 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter); 578 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter); 579 580 } break; 581 582 case RV_RENDER_OBJ_OP_UPDATE: { 583 s32 sampler_channel = 0; 584 if (ogl_ctx.bound_pip) { 585 // need to update the existing bound sampler 586 // ... or make sure we don't override a bound one 587 for (rv_uniform_t* u = ogl_ctx.bound_pip->uniform_desc_first; u; u = u->next) { 588 if (u->type == RV_UNIFORM_TEX) { 589 if (u ->last_val.v_tex == tex) { 590 // found our texture 591 break; 592 } 593 sampler_channel++; 594 } 595 } 596 } 597 glActiveTexture(GL_TEXTURE0 + sampler_channel); 598 glBindTexture(GL_TEXTURE_2D, tex->handle.u); 599 600 switch(tex->format) 601 { 602 case RV_TEXTURE_FORMAT_A8: glTexSubImage2D(GL_TEXTURE_2D, 0, c->obj.tex_update.sub_part.x, c->obj.tex_update.sub_part.y, c->obj.tex_update.sub_part.w, c->obj.tex_update.sub_part.h, GL_ALPHA, GL_UNSIGNED_BYTE, c->obj.tex_update.data); break; 603 case RV_TEXTURE_FORMAT_R8: glTexSubImage2D(GL_TEXTURE_2D, 0, c->obj.tex_update.sub_part.x, c->obj.tex_update.sub_part.y, c->obj.tex_update.sub_part.w, c->obj.tex_update.sub_part.h, GL_RED, GL_UNSIGNED_BYTE, c->obj.tex_update.data); break; 604 case RV_TEXTURE_FORMAT_RGB8: glTexSubImage2D(GL_TEXTURE_2D, 0, c->obj.tex_update.sub_part.x, c->obj.tex_update.sub_part.y, c->obj.tex_update.sub_part.w, c->obj.tex_update.sub_part.h, GL_RGB, GL_UNSIGNED_BYTE, c->obj.tex_update.data); break; 605 case RV_TEXTURE_FORMAT_RGBA8: glTexSubImage2D(GL_TEXTURE_2D, 0, c->obj.tex_update.sub_part.x, c->obj.tex_update.sub_part.y, c->obj.tex_update.sub_part.w, c->obj.tex_update.sub_part.h, GL_RGBA, GL_UNSIGNED_BYTE, c->obj.tex_update.data); break; 606 case RV_TEXTURE_FORMAT_RGBA16F: glTexSubImage2D(GL_TEXTURE_2D, 0, c->obj.tex_update.sub_part.x, c->obj.tex_update.sub_part.y, c->obj.tex_update.sub_part.w, c->obj.tex_update.sub_part.h, GL_RGBA, GL_FLOAT, c->obj.tex_update.data); break; 607 case RV_TEXTURE_FORMAT_RGBA32F: glTexSubImage2D(GL_TEXTURE_2D, 0, c->obj.tex_update.sub_part.x, c->obj.tex_update.sub_part.y, c->obj.tex_update.sub_part.w, c->obj.tex_update.sub_part.h, GL_RGBA, GL_FLOAT, c->obj.tex_update.data); break; 608 case RV_TEXTURE_FORMAT_DEPTH8: glTexSubImage2D(GL_TEXTURE_2D, 0, c->obj.tex_update.sub_part.x, c->obj.tex_update.sub_part.y, c->obj.tex_update.sub_part.w, c->obj.tex_update.sub_part.h, GL_DEPTH_COMPONENT, GL_FLOAT, c->obj.tex_update.data); break; 609 case RV_TEXTURE_FORMAT_DEPTH16: glTexSubImage2D(GL_TEXTURE_2D, 0, c->obj.tex_update.sub_part.x, c->obj.tex_update.sub_part.y, c->obj.tex_update.sub_part.w, c->obj.tex_update.sub_part.h, GL_DEPTH_COMPONENT, GL_FLOAT, c->obj.tex_update.data); break; 610 case RV_TEXTURE_FORMAT_DEPTH24: glTexSubImage2D(GL_TEXTURE_2D, 0, c->obj.tex_update.sub_part.x, c->obj.tex_update.sub_part.y, c->obj.tex_update.sub_part.w, c->obj.tex_update.sub_part.h, GL_DEPTH_COMPONENT, GL_FLOAT, c->obj.tex_update.data); break; 611 case RV_TEXTURE_FORMAT_DEPTH32F: glTexSubImage2D(GL_TEXTURE_2D, 0, c->obj.tex_update.sub_part.x, c->obj.tex_update.sub_part.y, c->obj.tex_update.sub_part.w, c->obj.tex_update.sub_part.h, GL_DEPTH_COMPONENT, GL_FLOAT, c->obj.tex_update.data); break; 612 case RV_TEXTURE_FORMAT_DEPTH24_STENCIL8: glTexSubImage2D(GL_TEXTURE_2D, 0, c->obj.tex_update.sub_part.x, c->obj.tex_update.sub_part.y, c->obj.tex_update.sub_part.w, c->obj.tex_update.sub_part.h, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, c->obj.tex_update.data); break; 613 case RV_TEXTURE_FORMAT_DEPTH32F_STENCIL8: glTexSubImage2D(GL_TEXTURE_2D, 0, c->obj.tex_update.sub_part.x, c->obj.tex_update.sub_part.y, c->obj.tex_update.sub_part.w, c->obj.tex_update.sub_part.h, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, c->obj.tex_update.data); break; 614 default: rv_unreachable(); break; 615 } 616 } break; 617 618 case RV_RENDER_OBJ_OP_BIND: { 619 rv_unreachable(); // textures are bound automatically by uniforms 620 } break; 621 622 case RV_RENDER_OBJ_OP_DESTROY: { 623 glDeleteTextures(1, &tex->handle.u); 624 tex->handle.u = 0; 625 } break; 626 } 627 } break; 628 629 case RV_COMMAND_UNIFORM_UPDATE: { 630 if (ogl_ctx.bound_pip) { 631 rv_uniform_t* desc = c->uniform_update.desc; 632 rv_uniform_variant_t* val = &c->uniform_update.value; 633 if (desc) { 634 // try to be smart about not re-uploading uniforms that haven't changed 635 if (!desc->has_been_set || !rv_mem_eq(&desc->last_val, val, sizeof(*val))) { 636 desc->last_val = *val; 637 desc->has_been_set = true; 638 639 switch (desc->type) { 640 case RV_UNIFORM_F32: glUniform1fv(desc->pipeline_uniform_handle.u, 1, &val->v_f32); break; 641 case RV_UNIFORM_VEC2: glUniform2fv(desc->pipeline_uniform_handle.u, 1, val->v_vec2.xy); break; 642 case RV_UNIFORM_VEC3: glUniform3fv(desc->pipeline_uniform_handle.u, 1, val->v_vec3.xyz); break; 643 case RV_UNIFORM_VEC4: glUniform4fv(desc->pipeline_uniform_handle.u, 1, val->v_vec4.xyzw); break; 644 case RV_UNIFORM_MAT4: glUniformMatrix4fv(desc->pipeline_uniform_handle.u, 1, GL_FALSE, val->v_mat4.elements); break; 645 case RV_UNIFORM_TEX: { 646 s32 sampler_channel = 0; 647 for (rv_uniform_t* u = ogl_ctx.bound_pip->uniform_desc_first; u; u = u->next) { 648 if (u->type == RV_UNIFORM_TEX) { 649 if (u == desc) { 650 // found our uniform, bind it 651 glActiveTexture(GL_TEXTURE0 + sampler_channel); 652 if (u->last_val.v_tex) { 653 glBindTexture(GL_TEXTURE_2D, u->last_val.v_tex->handle.u); 654 } else { 655 glBindTexture(GL_TEXTURE_2D, ogl_ctx.default_tex.handle.u); 656 } 657 break; 658 } 659 sampler_channel++; 660 } 661 } 662 663 } break; 664 case RV_UNIFORM_INVALID: rv_unreachable(); break; 665 } 666 } 667 } else { 668 rv_unreachable(); 669 } 670 } else { 671 rv_unreachable(); 672 } 673 } break; 674 675 case RV_COMMAND_DRAW: { 676 if (ogl_ctx.bound_pip) { 677 GLenum prim = rv_primitive_to_gl(c->draw.primitive); 678 // TODO(Samdal): instancing... 679 if (ogl_ctx.bound_ibo) { 680 681 GLenum itype = GL_UNSIGNED_INT; 682 switch (ogl_ctx.bound_ibo->elem_size) { 683 default: rv_unreachable(); 684 case 4: itype = GL_UNSIGNED_INT; break; 685 case 2: itype = GL_UNSIGNED_SHORT; break; 686 case 1: itype = GL_UNSIGNED_BYTE; break; 687 } 688 if (c->draw.instances) { 689 glDrawElementsInstanced(prim, c->draw.count, itype, (void*)(c->draw.first * ogl_ctx.bound_ibo->elem_size), c->draw.instances); 690 } else { 691 glDrawElements(prim, c->draw.count, itype, (void*)(c->draw.first * ogl_ctx.bound_ibo->elem_size)); 692 } 693 } else { 694 if (c->draw.instances) { 695 glDrawArraysInstanced(prim, c->draw.first, c->draw.count, c->draw.instances); 696 } else { 697 glDrawArrays(prim, c->draw.first, c->draw.count); 698 } 699 } 700 } else { 701 rv_unreachable(); 702 } 703 } break; 704 705 case RV_COMMAND_OBJ_FRAMEBUFFER: { 706 rv_framebuffer_t* fbuf = c->obj.framebuffer; 707 switch (c->obj.operation) { 708 case RV_RENDER_OBJ_OP_CREATE: { 709 glGenFramebuffers(1, &fbuf->handle.u); 710 } break; 711 712 case RV_RENDER_OBJ_OP_UPDATE: { 713 rv_unreachable(); 714 } break; 715 716 case RV_RENDER_OBJ_OP_BIND: { 717 ogl_bind_fbuf(fbuf); 718 } break; 719 720 case RV_RENDER_OBJ_OP_DESTROY: { 721 glDeleteFramebuffers(1, &fbuf->handle.u); 722 if (ogl_ctx.bound_fbuf == fbuf) { 723 ogl_ctx.bound_fbuf = NULL; 724 glBindFramebuffer(GL_FRAMEBUFFER, 0); 725 } 726 } break; 727 } 728 } break; 729 } 730 }