/** * @brief Upload data to a sub-position in already-created buffer. You could also use this function to * resize an existing buffer without uploading data, although it won't make the * buffer smaller. * @param data_offset Whether the data pointer should be offset by start or not. */ void R_UploadToSubBuffer(r_buffer_t *buffer, const size_t start, const size_t size, const void *data, const _Bool data_offset) { assert(buffer->bufnum != 0); // Check size. This is benign really, but it's usually a bug. if (!size) { Com_Warn("Attempted to upload 0 bytes to GPU\n"); return; } // Don't allow null ptrs since bufferSubData does not allow it. if (!data) { Com_Error(ERROR_DROP, "Fatal: attempted to upload null to GPU. bufferSubData does not allow this.\n"); } // offset ptr if requested if (start && data && data_offset) { data += start; } R_BindBuffer(buffer); // if the buffer isn't big enough to hold what we had already, // we have to resize the buffer const size_t total_size = start + size; if (total_size > buffer->size) { // if we passed a "start", the data is offset, so // just reset to null. This is an odd edge case and // it's fairly rare you'll be editing at the end first, // but who knows. if (start) { glBufferData(buffer->target, total_size, NULL, buffer->hint); R_GetError("Partial resize"); r_view.buffer_stats[buffer->type].num_full_uploads++; glBufferSubData(buffer->target, start, size, data); R_GetError("Partial update"); r_view.buffer_stats[buffer->type].num_partial_uploads++; } else { glBufferData(buffer->target, total_size, data, buffer->hint); R_GetError("Full resize"); r_view.buffer_stats[buffer->type].num_full_uploads++; } r_state.buffers_total_bytes -= buffer->size; r_state.buffers_total_bytes += total_size; buffer->size = total_size; } else { // just update the range we specified glBufferSubData(buffer->target, start, size, data); R_GetError("Updating existing buffer"); r_view.buffer_stats[buffer->type].num_partial_uploads++; } r_view.buffer_stats[buffer->type].size_uploaded += size; }
/* * @brief */ static void R_SetVertexBufferState(const r_model_t *mod, uint32_t mask) { // vertex array if (mask & R_ARRAY_VERTEX) R_BindBuffer(GL_VERTEX_ARRAY, GL_FLOAT, mod->vertex_buffer); // normals and tangents if (r_state.lighting_enabled) { if (mask & R_ARRAY_NORMAL) R_BindBuffer(GL_NORMAL_ARRAY, GL_FLOAT, mod->normal_buffer); if (r_bumpmap->value) { if ((mask & R_ARRAY_TANGENT) && mod->tangent_buffer) R_BindBuffer(GL_TANGENT_ARRAY, GL_FLOAT, mod->tangent_buffer); } } // diffuse texcoords if (texunit_diffuse.enabled) { if (mask & R_ARRAY_TEX_DIFFUSE) R_BindBuffer(GL_TEXTURE_COORD_ARRAY, GL_FLOAT, mod->texcoord_buffer); } // lightmap texcoords if (texunit_lightmap.enabled) { if (mask & R_ARRAY_TEX_LIGHTMAP) { R_SelectTexture(&texunit_lightmap); R_BindBuffer(GL_TEXTURE_COORD_ARRAY, GL_FLOAT, mod->lightmap_texcoord_buffer); R_SelectTexture(&texunit_diffuse); } } }
/** * @brief Upload data to an already-created buffer. You could also use this function to * resize an existing buffer without uploading data, although it won't make the * buffer smaller. */ void R_UploadToBuffer(r_buffer_t *buffer, const size_t size, const void *data) { assert(buffer->bufnum != 0); // Check size. This is benign really, but it's usually a bug. if (!size) { Com_Warn("Attempted to upload 0 bytes to GPU"); return; } R_BindBuffer(buffer); // if the buffer isn't big enough to hold what we had already, // we have to resize the buffer if (size > buffer->size) { r_state.buffers_total_bytes -= buffer->size; r_state.buffers_total_bytes += size; glBufferData(buffer->target, size, data, buffer->hint); R_GetError("Full resize"); r_view.buffer_stats[buffer->type].num_full_uploads++; buffer->size = size; } else { // just update the range we specified if (data) { glBufferSubData(buffer->target, 0, size, data); r_view.buffer_stats[buffer->type].num_partial_uploads++; R_GetError("Updating existing buffer"); } } r_view.buffer_stats[buffer->type].size_uploaded += size; }
/* * @brief */ void R_ResetArrayState(void) { uint32_t arrays, mask; mask = 0xffff, arrays = R_ArraysMask(); // resolve the desired arrays mask if (r_array_state.model == NULL) { const int32_t xor = r_array_state.arrays ^ arrays; if (!xor) // no changes, we're done return; // resolve what's left to turn on mask = arrays & xor; } else // vbo R_BindBuffer(0, 0, 0); // vertex array if (mask & R_ARRAY_VERTEX) R_BindDefaultArray(GL_VERTEX_ARRAY); // color array if (r_state.color_array_enabled) { if (mask & R_ARRAY_COLOR) R_BindDefaultArray(GL_COLOR_ARRAY); } // normals and tangents if (r_state.lighting_enabled) { if (mask & R_ARRAY_NORMAL) R_BindDefaultArray(GL_NORMAL_ARRAY); if (r_bumpmap->value) { if (mask & R_ARRAY_TANGENT) R_BindDefaultArray(GL_TANGENT_ARRAY); } } // diffuse texcoords if (texunit_diffuse.enabled) { if (mask & R_ARRAY_TEX_DIFFUSE) R_BindDefaultArray(GL_TEXTURE_COORD_ARRAY); } // lightmap texcoords if (texunit_lightmap.enabled) { if (mask & R_ARRAY_TEX_LIGHTMAP) { R_SelectTexture(&texunit_lightmap); R_BindDefaultArray(GL_TEXTURE_COORD_ARRAY); R_SelectTexture(&texunit_diffuse); } } r_array_state.model = NULL; r_array_state.arrays = arrays; }