为什么我的 OpenGL SSB 没有接收到主机发送的数据?

问题描述 投票:0回答:0

我将尝试创建尽可能多的 MRE,但让 OpenGL 在 Rust 中工作相当复杂,所以我将跳过样板文件和一些不必要的细节。

我正在尝试创建一个计算着色器,该着色器执行一些光线行进(大量数据,我还不需要查看图像等,因此我将进行计算而不是简单的 vert->frag 着色器设置。 )

我经历了使用 glutin 和 glow 获取 gl 上下文的繁琐过程,然后我编译了我的着色器。着色器编译很好,在着色器编译和计算之间没有错误,无论是 gl 还是其他,但是当我查看计算的输出时,我目前只是简单地镜像了一些发送到着色器的数据,我得到的都是 0。

数据输出、统一输入和计算工作正常。我已经以各种方式验证了这一点。但是,大部分数据来自 SSB。输入数据和输出数据使用两个独立的 SSB。通过 SSB 输入似乎不起作用,我假设我在尝试发送到 GPU 时做错了什么。

Rust 代码的粗略模型:

// we have a &glow::Context
let ctx = // fun gl boilerplate stuff.

// create data struct
#[repr(C)]
struct Data {
  // the layout of this struct might be the cause of the bug?
  thing_1: [u32; 2],
  thing_2: f32,
  thing_3: [f32; 3],
}
// impl Default for Data

// setup buffer and data
let buf = ctx.create_buffer().unwrap();
ctx.bind_buffer(glow::SHADER_STORAGE_BUFFER, Some(buf));

// there's a reason this is a vec. it should be irrelevant.
let mut lots_of_data = vec![Data::default(); 1024];

// modify the first entry for testing later
lots_of_data[0].thing_1 = [u32::MAX, u32::MAX];
lots_of_data[0].thing_2 = -1234.0;
lots_of_data[0].thing_3 = [f32::NAN, f32::NAN, f32::NAN];

// easiest way to send data to a buffer is with a u8 slice.
// this might also be where the problem lies. this is a fairly
// dense area of opengl's standard, and not particularly
// well-documented - certainly not in the context of rust. so,
// I'm unsure if the problem lies in the way i'm passing data
// or somewhere else entirely, and i'm not really sure how to
// tell.
let data_u8 = std::slice::from_raw_parts(
  lots_of_data.as_ptr().cast(),
  lots_of_data.len() * std::mem::size_of::<Data>(),
);
ctx.buffer_data_u8_slice(
  glow::SHADER_STORAGE_BUFFER,
  data_u8,
  glow::DYNAMIC_COPY
);

// repeat the above process for an output buffer

let program = ctx.create_program().unwrap();

// do shader boilerplate stuff

// use program, set uniforms, etc.
ctx.use_program(Some(program));
let location = ctx.get_uniform_location(program, "u_test");
ctx.uniform_1_f32(location.as_ref(), 42.0); // set uniform to something unique
ctx.bind_buffer_base(glow::SHADER_STORAGE_BUFFER, 0, Some(buf));
// we glossed over creating out_buf, but here we're binding it for output
ctx.bind_buffer_base(glow::SHADER_STORAGE_BUFFER, 1, Some(out_buf));

// run the shader
ctx.dispatch_compute(1000, 1, 1);

// for simplicity's sake, let's say my output data is a vec4
let mut out_raw = vec![0u8; 1024 * std::mem::size_of::<[f32; 4]>()];
// convert the u8s back into "vec4"s
ctx.get_buffer_sub_data(glow::SHADER_STORAGE_BUFFER, 0, &mut data_raw);
let out: &[[f32; 4]] = std::slice::from_raw_parts(
  out_raw.as_ptr().cast(),
  1024
);

// 1024 instances of [42.0, 0.0, 0.0, 0.0]. yes, even the 1st instance. no idea why.
dbg!(out);

着色器的粗略模型:

#version 440
layout(local_size_x = 8) in; // maybe this line? ngl, i copy+pasted

// same layout as Rust struct. maybe?
struct Data {
  uvec2 thing1;
  float thing2;
  vec3 thing_3;
};

// create SSBs
layout(shared, binding = 0) readonly buffer InputData { Data input_data[]; };
layout(shared, binding = 1) writeonly buffer OutputData { vec4 output_data[]; };

// uniforms
uniform float u_test;

void main() {
  // grab this thread's data
  Data data = input_data[gl_GlobalInvocationID.x];

  // create easily recognizable output data
  vec4 out = vec4(
    u_test,
    float(data.thing1.x),
    data.thing2,
    data.thing3.x
  );

  // send output data
  output_data[gl_GlobalInvocationID.x] = out;
}
opengl rust glsl compute-shader
© www.soinside.com 2019 - 2024. All rights reserved.