Hello there. Currently working on a piece of software that would benefit from the use of MDI. My program works fine on all Windows machines I’ve tested that use a Discrete GPU. However, the exact same program crashes with GL_INVALID_OPERATION
on my glMultiDrawElementsIndirect
draw call. After some debugging, it appears it is crashing due to the igxelpicd64.dll
driver, specifically a call to DrvValidateVersion
at call address 0x9
. My Intel Integrated CPU is on driver version 32.0.101.6299. However, on Intel’s website, the debug symbols download page only goes up to 32.0.101.6129, so this might actually not be the correct function name. In any case, my code is below. It is contained to just this file. For those wondering, the programming language is called Jai. It has compatible OpenGL bindings.
window : Window_Type;
should_close : bool = false;
shader_program : u32 = 0;
VAO : u32 = 0;
VBO : u32 = 0;
EBO : u32 = 0;
IBO : u32 = 0;
vertex_buffer : [..] Vertex;
index_buffer : [..] u64;
indirect_buffer : [..] IndirectCommand;
IndirectCommand :: struct {
count : u32;
instance_count : u32;
first_index : u32;
base_vertex : s32;
base_instance : u32;
}
Vertex :: struct {
position : Vector3;
color : Vector3;
}
SAMPLE_VERTS : [..] Vertex = xx Vertex.[
.{.{-.5, -.5, 0}, .{1, 0, 0}},
.{.{ .5, -.5, 0}, .{0, 1, 0}},
.{.{ .5, .5, 0}, .{0, 0, 1}},
.{.{-.5, .5, 0}, .{1, 1, 1}},
];
SAMPLE_INDXS : [..] u32 = xx u32.[
0, 1, 2,
2, 3, 0
];
main :: () {
print("Hello world!\n");
create_game_window();
create_opengl_context();
setup_render();
while !should_close {
// Poll events
update_window_events();
for events_this_frame {
if it.type == .QUIT {
should_close = true;
}
}
draw_frame();
}
}
create_game_window :: () {
window_width : int : 640;
window_height : int : 480;
window_title : string : "This shit dont work";
window = create_window(window_width, window_height,
window_title,
wanted_msaa = 0);
return;
}
create_opengl_context :: () {
gl_create_context(window, 4, 5, false, true, 0);
gl_load(*gl);
gl_enable_debug_output(true);
glViewport(0, 0, 640, 480);
//glEnable(GL_CULL_FACE);
//glCullFace(GL_BACK);
//glDebugMessageCallback(debug_message_callback,xx 0);
}
setup_render :: () {
// Create shader programs
vert_file_location := tprint("%/shader.vert", get_program_data_dir());
frag_file_location := tprint("%/shader.frag", get_program_data_dir());
vert, vert_loaded := read_entire_file(vert_file_location);
frag, frag_loaded := read_entire_file(frag_file_location);
vertex_shader : u32;
vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, *vert.data, null);
glCompileShader(vertex_shader);
fragment_shader : u32;
fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, *frag.data, null);
glCompileShader(fragment_shader);
shader_program = glCreateProgram();
glAttachShader(shader_program, vertex_shader);
glAttachShader(shader_program, fragment_shader);
glLinkProgram(shader_program);
success : s32 = 0;
result := glGetProgramiv(shader_program, GL_LINK_STATUS, *success);
print("Result: %\n", success);
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
glUseProgram(shader_program);
// Generate Buffers
glGenVertexArrays(1, *VAO);
glGenBuffers(1, *VBO);
glGenBuffers(1, *EBO);
glGenBuffers(1, *IBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, IBO);
// Preallocated Vertex and Index buffers
array_resize(*vertex_buffer, 4);
array_resize(*index_buffer, 6);
// Size of allocated space, in bytes
indirect : IndirectCommand = .{
6, // Element Count
1, // Instance Count
0, // First Index
0, // Base Vertex
0 // Base Index
};
array_add(*indirect_buffer, indirect);
indirect_buffer_size : s64 = indirect_buffer.count * size_of(IndirectCommand);
vertex_buffer_size : s64 = SAMPLE_VERTS.count * size_of(Vertex);
index_buffer_size : s64 = SAMPLE_INDXS.count * size_of(u64);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_TRUE, 6 * size_of(float), cast(*void) 0); // Position Attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * size_of(float), cast(*void) (3 * size_of(float))); // Color Attribute
// Preallocate the data by sending the empty, reserved arrays.
glBufferData(GL_ARRAY_BUFFER, vertex_buffer_size, vertex_buffer.data, GL_DYNAMIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_buffer_size, index_buffer.data, GL_DYNAMIC_DRAW);
glBufferData(GL_DRAW_INDIRECT_BUFFER, indirect_buffer_size, indirect_buffer.data, GL_DYNAMIC_DRAW);
// Much later in the program, upload vertex and index data.
glBufferData(GL_ARRAY_BUFFER, vertex_buffer_size, SAMPLE_VERTS.data, GL_DYNAMIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_buffer_size, SAMPLE_INDXS.data, GL_DYNAMIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, indirect_buffer_size, SAMPLE_VERTS.data);
}
swap_buffers :: (window: Window_Type, vsync := true) { //@TODO: Implement other platforms and vsync
#if OS == .WINDOWS {
dc := GetDC(window);
SwapBuffers(dc);
}
}
draw_frame :: () {
glClearColor(.5, .5, 1, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, IBO);
glBufferData(GL_DRAW_INDIRECT_BUFFER, size_of(IndirectCommand) * indirect_buffer.count, indirect_buffer.data, GL_DYNAMIC_DRAW);
aspect_ratio : float = (640 / 480);
model := make_translation_matrix4(.{0, 0, 0});
view := make_look_at_matrix(.{2, 2, 2}, .{0, 0, 0}, .{0, 0, 1}, false);
proj := transpose(make_projection_matrix(75.0 * PI / 180.0, aspect_ratio, 0.1, 1000.0, 0, 0, true));
model_location := glGetUniformLocation(shader_program, "model");
glUniformMatrix4fv(model_location, 1, GL_FALSE, *transpose(model).coef[0][0]);
view_location := glGetUniformLocation(shader_program, "view");
glUniformMatrix4fv(view_location, 1, GL_FALSE, *transpose(view).coef[0][0]);
projection_location := glGetUniformLocation(shader_program, "proj");
glUniformMatrix4fv(projection_location, 1, GL_FALSE, *proj.coef[0][0]);
glFinish();
//glDrawElements(GL_TRIANGLES, xx index_buffer.count, GL_UNSIGNED_INT, cast(*void) 0);
glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, xx 0, xx indirect_buffer.count, 0);
swap_buffers(window);
}
debug_message_callback :: (source : GLenum, type : GLenum, id : GLuint, severity : GLenum, length : GLsizei, message : *u8, userParam : *void) -> void #c_call
{
new_context : Context;
push_context new_context {
print("GL CALLBACK: % type = %, severity = %, message = %\n", "foo", type, severity, to_string(message));
}
}
#scope_file
#import "Basic";
#import "GL";
#import "Window_Creation";
#import "Windows";
#import "Input";
#import "String";
#import "File";
#import "System";
#import "Math";
get_program_data_dir :: () -> string {
dir := trim_right(path_strip_filename(get_path_of_running_executable()), "/");
return copy_string(dir);
}
After asking a round, many people described that Intel OpenGL Drivers are known to be broken with Integrated GPUs and MDI (Multi Draw Indirect). I wanted to create this post so people know that this is apparently not a solo issue. If anyone has any insight on this issue, please let me know. Thank you.