This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/gpu/opengl/gl_vertex_array.cc

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

167 lines
5.4 KiB
C++
Raw Normal View History

/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2016 by Mike Erwin. All rights reserved. */
/** \file
* \ingroup gpu
*/
#include "gpu_shader_interface.hh"
#include "gpu_vertex_buffer_private.hh"
#include "gl_batch.hh"
#include "gl_context.hh"
#include "gl_index_buffer.hh"
DRWManager: New implementation. This is a new implementation of the draw manager using modern rendering practices and GPU driven culling. This only ports features that are not considered deprecated or to be removed. The old DRW API is kept working along side this new one, and does not interfeer with it. However this needed some more hacking inside the draw_view_lib.glsl. At least the create info are well separated. The reviewer might start by looking at `draw_pass_test.cc` to see the API in usage. Important files are `draw_pass.hh`, `draw_command.hh`, `draw_command_shared.hh`. In a nutshell (for a developper used to old DRW API): - `DRWShadingGroups` are replaced by `Pass<T>::Sub`. - Contrary to DRWShadingGroups, all commands recorded inside a pass or sub-pass (even binds / push_constant / uniforms) will be executed in order. - All memory is managed per object (except for Sub-Pass which are managed by their parent pass) and not from draw manager pools. So passes "can" potentially be recorded once and submitted multiple time (but this is not really encouraged for now). The only implicit link is between resource lifetime and `ResourceHandles` - Sub passes can be any level deep. - IMPORTANT: All state propagate from sub pass to subpass. There is no state stack concept anymore. Ensure the correct render state is set before drawing anything using `Pass::state_set()`. - The drawcalls now needs a `ResourceHandle` instead of an `Object *`. This is to remove any implicit dependency between `Pass` and `Manager`. This was a huge problem in old implementation since the manager did not know what to pull from the object. Now it is explicitly requested by the engine. - The pases need to be submitted to a `draw::Manager` instance which can be retrieved using `DRW_manager_get()` (for now). Internally: - All object data are stored in contiguous storage buffers. Removing a lot of complexity in the pass submission. - Draw calls are sorted and visibility tested on GPU. Making more modern culling and better instancing usage possible in the future. - Unit Tests have been added for regression testing and avoid most API breakage. - `draw::View` now contains culling data for all objects in the scene allowing caching for multiple views. - Bounding box and sphere final setup is moved to GPU. - Some global resources locations have been hardcoded to reduce complexity. What is missing: - ~~Workaround for lack of gl_BaseInstanceARB.~~ Done - ~~Object Uniform Attributes.~~ Done (Not in this patch) - Workaround for hardware supporting a maximum of 8 SSBO. Reviewed By: jbakker Differential Revision: https://developer.blender.org/D15817
2022-09-02 18:30:48 +02:00
#include "gl_storage_buffer.hh"
#include "gl_vertex_buffer.hh"
#include "gl_vertex_array.hh"
namespace blender::gpu {
/* -------------------------------------------------------------------- */
/** \name Vertex Array Bindings
* \{ */
2022-08-17 15:43:17 +10:00
/** Returns enabled vertex pointers as a bit-flag (one bit per attribute). */
static uint16_t vbo_bind(const ShaderInterface *interface,
const GPUVertFormat *format,
uint v_first,
uint v_len,
const bool use_instancing)
{
uint16_t enabled_attrib = 0;
const uint attr_len = format->attr_len;
uint stride = format->stride;
uint offset = 0;
GLuint divisor = (use_instancing) ? 1 : 0;
for (uint a_idx = 0; a_idx < attr_len; a_idx++) {
const GPUVertAttr *a = &format->attrs[a_idx];
if (format->deinterleaved) {
offset += ((a_idx == 0) ? 0 : format->attrs[a_idx - 1].size) * v_len;
stride = a->size;
}
else {
offset = a->offset;
}
/* This is in fact an offset in memory. */
const GLvoid *pointer = (const GLubyte *)intptr_t(offset + v_first * stride);
const GLenum type = to_gl(static_cast<GPUVertCompType>(a->comp_type));
for (uint n_idx = 0; n_idx < a->name_len; n_idx++) {
const char *name = GPU_vertformat_attr_name_get(format, a, n_idx);
const ShaderInput *input = interface->attr_get(name);
if (input == nullptr || input->location == -1) {
continue;
}
enabled_attrib |= (1 << input->location);
2020-11-06 12:51:49 +11:00
if (ELEM(a->comp_len, 16, 12, 8)) {
BLI_assert(a->fetch_mode == GPU_FETCH_FLOAT);
BLI_assert(a->comp_type == GPU_COMP_F32);
for (int i = 0; i < a->comp_len / 4; i++) {
glEnableVertexAttribArray(input->location + i);
glVertexAttribDivisor(input->location + i, divisor);
glVertexAttribPointer(
input->location + i, 4, type, GL_FALSE, stride, (const GLubyte *)pointer + i * 16);
}
}
else {
glEnableVertexAttribArray(input->location);
glVertexAttribDivisor(input->location, divisor);
switch (a->fetch_mode) {
case GPU_FETCH_FLOAT:
case GPU_FETCH_INT_TO_FLOAT:
glVertexAttribPointer(input->location, a->comp_len, type, GL_FALSE, stride, pointer);
break;
case GPU_FETCH_INT_TO_FLOAT_UNIT:
glVertexAttribPointer(input->location, a->comp_len, type, GL_TRUE, stride, pointer);
break;
case GPU_FETCH_INT:
glVertexAttribIPointer(input->location, a->comp_len, type, stride, pointer);
break;
}
}
}
}
return enabled_attrib;
}
void GLVertArray::update_bindings(const GLuint vao,
const GPUBatch *batch_, /* Should be GLBatch. */
const ShaderInterface *interface,
const int base_instance)
{
const GLBatch *batch = static_cast<const GLBatch *>(batch_);
uint16_t attr_mask = interface->enabled_attr_mask_;
glBindVertexArray(vao);
/* Reverse order so first VBO'S have more prevalence (in term of attribute override). */
for (int v = GPU_BATCH_VBO_MAX_LEN - 1; v > -1; v--) {
GLVertBuf *vbo = batch->verts_(v);
if (vbo) {
vbo->bind();
attr_mask &= ~vbo_bind(interface, &vbo->format, 0, vbo->vertex_len, false);
}
}
for (int v = GPU_BATCH_INST_VBO_MAX_LEN - 1; v > -1; v--) {
GLVertBuf *vbo = batch->inst_(v);
if (vbo) {
vbo->bind();
attr_mask &= ~vbo_bind(interface, &vbo->format, base_instance, vbo->vertex_len, true);
}
}
DRWManager: New implementation. This is a new implementation of the draw manager using modern rendering practices and GPU driven culling. This only ports features that are not considered deprecated or to be removed. The old DRW API is kept working along side this new one, and does not interfeer with it. However this needed some more hacking inside the draw_view_lib.glsl. At least the create info are well separated. The reviewer might start by looking at `draw_pass_test.cc` to see the API in usage. Important files are `draw_pass.hh`, `draw_command.hh`, `draw_command_shared.hh`. In a nutshell (for a developper used to old DRW API): - `DRWShadingGroups` are replaced by `Pass<T>::Sub`. - Contrary to DRWShadingGroups, all commands recorded inside a pass or sub-pass (even binds / push_constant / uniforms) will be executed in order. - All memory is managed per object (except for Sub-Pass which are managed by their parent pass) and not from draw manager pools. So passes "can" potentially be recorded once and submitted multiple time (but this is not really encouraged for now). The only implicit link is between resource lifetime and `ResourceHandles` - Sub passes can be any level deep. - IMPORTANT: All state propagate from sub pass to subpass. There is no state stack concept anymore. Ensure the correct render state is set before drawing anything using `Pass::state_set()`. - The drawcalls now needs a `ResourceHandle` instead of an `Object *`. This is to remove any implicit dependency between `Pass` and `Manager`. This was a huge problem in old implementation since the manager did not know what to pull from the object. Now it is explicitly requested by the engine. - The pases need to be submitted to a `draw::Manager` instance which can be retrieved using `DRW_manager_get()` (for now). Internally: - All object data are stored in contiguous storage buffers. Removing a lot of complexity in the pass submission. - Draw calls are sorted and visibility tested on GPU. Making more modern culling and better instancing usage possible in the future. - Unit Tests have been added for regression testing and avoid most API breakage. - `draw::View` now contains culling data for all objects in the scene allowing caching for multiple views. - Bounding box and sphere final setup is moved to GPU. - Some global resources locations have been hardcoded to reduce complexity. What is missing: - ~~Workaround for lack of gl_BaseInstanceARB.~~ Done - ~~Object Uniform Attributes.~~ Done (Not in this patch) - Workaround for hardware supporting a maximum of 8 SSBO. Reviewed By: jbakker Differential Revision: https://developer.blender.org/D15817
2022-09-02 18:30:48 +02:00
if (batch->resource_id_buf) {
const ShaderInput *input = interface->attr_get("drw_ResourceID");
if (input) {
dynamic_cast<GLStorageBuf *>(unwrap(batch->resource_id_buf))->bind_as(GL_ARRAY_BUFFER);
glEnableVertexAttribArray(input->location);
glVertexAttribDivisor(input->location, 1);
glVertexAttribIPointer(
input->location, 1, to_gl(GPU_COMP_I32), sizeof(uint32_t), (GLvoid *)nullptr);
attr_mask &= ~(1 << input->location);
}
}
if (attr_mask != 0 && GLContext::vertex_attrib_binding_support) {
for (uint16_t mask = 1, a = 0; a < 16; a++, mask <<= 1) {
if (attr_mask & mask) {
GLContext *ctx = GLContext::get();
/* This replaces glVertexAttrib4f(a, 0.0f, 0.0f, 0.0f, 1.0f); with a more modern style.
* Fix issues for some drivers (see T75069). */
glBindVertexBuffer(a, ctx->default_attr_vbo_, intptr_t(0), intptr_t(0));
glEnableVertexAttribArray(a);
glVertexAttribFormat(a, 4, GL_FLOAT, GL_FALSE, 0);
glVertexAttribBinding(a, a);
}
}
}
if (batch->elem) {
/* Binds the index buffer. This state is also saved in the VAO. */
static_cast<GLIndexBuf *>(unwrap(batch->elem))->bind();
}
}
void GLVertArray::update_bindings(const GLuint vao,
const uint v_first,
const GPUVertFormat *format,
const ShaderInterface *interface)
{
glBindVertexArray(vao);
vbo_bind(interface, format, v_first, 0, false);
}
/** \} */
} // namespace blender::gpu