use explicit binding for textures

- prevents dozens of glUniform1i calls when drawing stuff, thus improving performance by 5-10% (more on WebAssembly, where each gl call is passed through JS)
This commit is contained in:
Dmitry Stepanov
2024-10-11 12:25:38 +03:00
parent b97c9d5800
commit b622e4ec87
4 changed files with 49 additions and 26 deletions
+14 -2
View File
@@ -52,10 +52,15 @@ pub enum BufferDataUsage {
},
}
pub enum TextureShaderLocation {
Uniform(UniformLocation),
ExplicitBinding(usize),
}
pub enum ResourceBinding<'a> {
Texture {
texture: Rc<RefCell<dyn GpuTexture>>,
shader_location: UniformLocation,
shader_location: TextureShaderLocation,
},
Buffer {
buffer: &'a dyn Buffer,
@@ -71,7 +76,14 @@ impl<'a> ResourceBinding<'a> {
) -> Self {
Self::Texture {
texture: texture.clone(),
shader_location: shader_location.clone(),
shader_location: TextureShaderLocation::Uniform(shader_location.clone()),
}
}
pub fn texture_with_binding(texture: &Rc<RefCell<dyn GpuTexture>>, binding: usize) -> Self {
Self::Texture {
texture: texture.clone(),
shader_location: TextureShaderLocation::ExplicitBinding(binding),
}
}
}
+11 -8
View File
@@ -18,7 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
use crate::framebuffer::BufferDataUsage;
use crate::framebuffer::{BufferDataUsage, TextureShaderLocation};
use crate::gl::geometry_buffer::GlGeometryBuffer;
use crate::{
buffer::{Buffer, BufferKind},
@@ -475,13 +475,16 @@ fn pre_draw(
} => {
let texture = texture.borrow();
let texture = texture.as_any().downcast_ref::<GlTexture>().unwrap();
unsafe {
server
.gl
.uniform_1_i32(Some(&shader_location.id), texture_unit)
};
texture.bind(server, texture_unit as u32);
texture_unit += 1;
match shader_location {
TextureShaderLocation::Uniform(uniform) => {
unsafe { server.gl.uniform_1_i32(Some(&uniform.id), texture_unit) };
texture.bind(server, texture_unit as u32);
texture_unit += 1;
}
TextureShaderLocation::ExplicitBinding(binding) => {
texture.bind(server, *binding as u32);
}
}
}
ResourceBinding::Buffer {
buffer,
+18 -1
View File
@@ -281,7 +281,24 @@ impl GlProgram {
initial_source.insert_str(0, &texture_bindings);
}
Self::from_source(server, name, &vertex_source, &fragment_source)
let program = Self::from_source(server, name, &vertex_source, &fragment_source)?;
unsafe {
server.set_program(Some(program.id));
let mut texture_unit_index = 0;
for property in properties {
if let PropertyKind::Sampler { .. } = property.kind {
if let Some(location) =
server.gl.get_uniform_location(program.id, &property.name)
{
server.gl.uniform_1_i32(Some(&location), texture_unit_index);
}
texture_unit_index += 1;
}
}
}
Ok(program)
}
pub fn from_source(
+6 -15
View File
@@ -45,7 +45,7 @@ use crate::{
buffer::Buffer,
error::FrameworkError,
framebuffer::{FrameBuffer, ResourceBindGroup, ResourceBinding},
gpu_program::{BuiltInUniformBlock, GpuProgram},
gpu_program::BuiltInUniformBlock,
gpu_texture::GpuTexture,
server::GraphicsServer,
uniform::StaticUniformBuffer,
@@ -170,16 +170,15 @@ impl<'a> BundleRenderContext<'a> {
&mut self,
server: &dyn GraphicsServer,
material: &Material,
program: &dyn GpuProgram,
material_bindings: &mut ArrayVec<ResourceBinding, 32>,
) -> Result<(), FrameworkError> {
let shader = material.shader().data_ref();
for property in shader.definition.properties.iter() {
let binding = material_bindings.len();
if property.name.as_str() == "fyrox_sceneDepth" {
if let Some(scene_depth) = self.scene_depth.as_ref() {
if let Ok(location) = program.uniform_location(&property.name) {
material_bindings.push(ResourceBinding::texture(scene_depth, &location));
}
material_bindings
.push(ResourceBinding::texture_with_binding(scene_depth, binding));
}
} else if let Some(PropertyValue::Sampler { value, fallback }) =
material.properties().get(&property.name)
@@ -193,10 +192,7 @@ impl<'a> BundleRenderContext<'a> {
SamplerFallback::Black => self.black_dummy,
SamplerFallback::Volume => self.volume_dummy,
});
if let Ok(uniform) = program.uniform_location(&property.name) {
material_bindings.push(ResourceBinding::texture(texture, &uniform));
}
material_bindings.push(ResourceBinding::texture_with_binding(texture, binding));
}
}
@@ -481,12 +477,7 @@ impl RenderDataBundle {
};
let mut material_bindings = ArrayVec::<ResourceBinding, 32>::new();
render_context.apply_material(
server,
material,
&*render_pass.program,
&mut material_bindings,
)?;
render_context.apply_material(server, material, &mut material_bindings)?;
let block_locations = render_pass.program.built_in_uniform_blocks();