diff options
Diffstat (limited to 'source/blender')
78 files changed, 2724 insertions, 104 deletions
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h index d6cabbc1236..d9cb8f44bb7 100644 --- a/source/blender/blenkernel/BKE_global.h +++ b/source/blender/blenkernel/BKE_global.h @@ -158,7 +158,8 @@ enum { G_DEBUG_XR = (1 << 19), /* XR/OpenXR messages */ G_DEBUG_XR_TIME = (1 << 20), /* XR/OpenXR timing messages */ - G_DEBUG_GHOST = (1 << 21), /* Debug GHOST module. */ + G_DEBUG_GHOST = (1 << 21), /* Debug GHOST module. */ + G_DEBUG_VK_CONTEXT = (1 << 22), /* not a debug flag, TODO move it. */ }; #define G_DEBUG_ALL \ diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index b8ca22d33d3..f3f1655f9e4 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -530,7 +530,7 @@ if(WITH_GTESTS) set(TEST_SRC tests/draw_testing.cc tests/shaders_test.cc - + tests/performance_test.cc tests/draw_testing.hh ) set(TEST_INC diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c index 9a85037ac77..a9bdbb76ebb 100644 --- a/source/blender/draw/engines/eevee/eevee_lightcache.c +++ b/source/blender/draw/engines/eevee/eevee_lightcache.c @@ -612,7 +612,7 @@ static void eevee_lightbake_context_enable(EEVEE_LightBake *lbake) if (lbake->gl_context) { DRW_opengl_render_context_enable(lbake->gl_context); if (lbake->gpu_context == NULL) { - lbake->gpu_context = GPU_context_create(NULL); + lbake->gpu_context = GPU_context_create(NULL, lbake->gl_context); } DRW_gpu_render_context_enable(lbake->gpu_context); } diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl index f349806d37e..1d552019370 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl @@ -59,7 +59,7 @@ void main() { ivec2 tex_size = textureSize(cocBuffer, 0); - int t_id = gl_VertexID / 3; /* Triangle Id */ + int t_id = gl_VertexIndex / 3; /* Triangle Id */ /* Some math to get the target pixel. */ ivec2 texelco = ivec2(t_id % spritePerRow, t_id / spritePerRow) * 2; @@ -118,7 +118,7 @@ void main() */ /* Generate Triangle : less memory fetches from a VBO */ - int v_id = gl_VertexID % 3; /* Vertex Id */ + int v_id = gl_VertexIndex % 3; /* Vertex Id */ gl_Position.x = float(v_id / 2) * extend - 1.0; /* int divisor round down */ gl_Position.y = float(v_id % 2) * extend - 1.0; gl_Position.z = 0.0; diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl index c9af2753baa..93225a75cda 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl @@ -30,8 +30,8 @@ const vec2 pos[6] = vec2[6](vec2(-1.0, -1.0), void main() { - pid = 1 + (gl_VertexID / 6); /* +1 for the world */ - int vert_id = gl_VertexID % 6; + pid = 1 + (gl_VertexIndex / 6); /* +1 for the world */ + int vert_id = gl_VertexIndex % 6; quadCoord = pos[vert_id]; diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl index 6fefe1319bd..fcadf9dbd82 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl @@ -23,8 +23,8 @@ const vec2 pos[6] = vec2[6](vec2(-1.0, -1.0), void main() { - int cell_id = gl_VertexID / 6; - int vert_id = gl_VertexID % 6; + int cell_id = gl_VertexIndex / 6; + int vert_id = gl_VertexIndex % 6; vec3 ls_cell_location; /* Keep in sync with update_irradiance_probe */ diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_vert.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_vert.glsl index 588cd402bb3..4b79ca97e7c 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_vert.glsl @@ -4,9 +4,9 @@ out vec2 vPos; void main() { - int v = gl_VertexID % 3; + int v = gl_VertexIndex % 3; vPos.x = -1.0 + float((v & 1) << 2); vPos.y = -1.0 + float((v & 2) << 1); - instance = gl_VertexID / 3; + instance = gl_VertexIndex / 3; } diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl index b70747ecec3..0bc735591ca 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl @@ -8,8 +8,8 @@ RESOURCE_ID_VARYING void main() { /* Generate Triangle : less memory fetches from a VBO */ - int v_id = gl_VertexID % 3; /* Vertex Id */ - int t_id = gl_VertexID / 3; /* Triangle Id */ + int v_id = gl_VertexIndex % 3; /* Vertex Id */ + int t_id = gl_VertexIndex / 3; /* Triangle Id */ /* Crappy diagram * ex 1 diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_vert.glsl index 07734d19972..31eda3670e9 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_vert.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_vert.glsl @@ -5,7 +5,7 @@ out vec4 offset[3]; void main() { - int v = gl_VertexID % 3; + int v = gl_VertexIndex % 3; float x = -1.0 + float((v & 1) << 2); float y = -1.0 + float((v & 2) << 1); gl_Position = vec4(x, y, 1.0, 1.0); diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl index 36a52e05a4a..8db831255cd 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl @@ -245,7 +245,7 @@ in vec4 col1; in vec4 col2; in vec4 fcol1; /* WARNING: Max attribute count is actually 14 because OSX OpenGL implementation - * considers gl_VertexID and gl_InstanceID as vertex attribute. (see T74536) */ + * considers gl_VertexIndex and gl_InstanceID as vertex attribute. (see T74536) */ # define stroke_id1 ma1.y # define point_id1 ma1.z # define thickness1 pos1.w @@ -408,8 +408,8 @@ void stroke_vertex() mat4 model_mat = model_matrix_get(); /* Avoid using a vertex attribute for quad positioning. */ - float x = float(gl_VertexID & 1) * 2.0 - 1.0; /* [-1..1] */ - float y = float(gl_VertexID & 2) - 1.0; /* [-1..1] */ + float x = float(gl_VertexIndex & 1) * 2.0 - 1.0; /* [-1..1] */ + float y = float(gl_VertexIndex & 2) - 1.0; /* [-1..1] */ bool use_curr = is_dot || (x == -1.0); diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_vert.glsl index 0c5260a9ec4..34b28f1f5b8 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_vert.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_vert.glsl @@ -4,7 +4,7 @@ uniform vec4 gpModelMatrix[4]; void main() { mat4 model_matrix = mat4(gpModelMatrix[0], gpModelMatrix[1], gpModelMatrix[2], gpModelMatrix[3]); - int v = gl_VertexID % 3; + int v = gl_VertexIndex % 3; float x = -1.0 + float((v & 1) << 2); float y = -1.0 + float((v & 2) << 1); gl_Position = ViewProjectionMatrix * (model_matrix * vec4(x, y, 0.0, 1.0)); diff --git a/source/blender/draw/engines/overlay/shaders/antialiasing_vert.glsl b/source/blender/draw/engines/overlay/shaders/antialiasing_vert.glsl index 8cf8ba121ed..3118e488efc 100644 --- a/source/blender/draw/engines/overlay/shaders/antialiasing_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/antialiasing_vert.glsl @@ -3,7 +3,7 @@ out vec2 uvs; void main() { - int v = gl_VertexID % 3; + int v = gl_VertexIndex % 3; float x = float((v & 1) << 2); float y = float((v & 2) << 1); gl_Position = vec4(x - 1.0, y - 1.0, 1.0, 1.0); diff --git a/source/blender/draw/engines/overlay/shaders/clipbound_vert.glsl b/source/blender/draw/engines/overlay/shaders/clipbound_vert.glsl index 1bfa5dadc32..532b7abc433 100644 --- a/source/blender/draw/engines/overlay/shaders/clipbound_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/clipbound_vert.glsl @@ -3,7 +3,7 @@ uniform vec3 boundbox[8]; void main() { - vec3 world_pos = boundbox[gl_VertexID]; + vec3 world_pos = boundbox[gl_VertexIndex]; gl_Position = point_world_to_ndc(world_pos); /* Result in a position at 1.0 (far plane). Small epsilon to avoid precision issue. diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_curve_wire_vert.glsl index 5dd8e579db3..190516efb78 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_curve_wire_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/edit_curve_wire_vert.glsl @@ -16,7 +16,7 @@ void main() float flip = (gl_InstanceID != 0) ? -1.0 : 1.0; - if (gl_VertexID % 2 == 0) { + if (gl_VertexIndex % 2 == 0) { final_pos += normalSize * rad * (flip * nor - tan); } diff --git a/source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl index 5aa7fe78e4e..070de772723 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl @@ -14,8 +14,8 @@ void main() GPU_INTEL_VERTEX_SHADER_WORKAROUND vec2 pos; - pos.x = float(gl_VertexID % 2); - pos.y = float(gl_VertexID / 2) / float(halfLineCount - 1); + pos.x = float(gl_VertexIndex % 2); + pos.y = float(gl_VertexIndex / 2) / float(halfLineCount - 1); if (pos.y > 1.0) { pos.xy = pos.yx; diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl index 944eb41058e..95c90b16551 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl @@ -17,7 +17,7 @@ void main() vec4 pos_4d = ModelMatrix * vec4(local_pos + screen_pos, 1.0); gl_Position = ViewProjectionMatrix * pos_4d; /* Manual stipple: one segment out of 2 is transparent. */ - finalColor = ((gl_VertexID & 1) == 0) ? colorSkinRoot : vec4(0.0); + finalColor = ((gl_VertexIndex & 1) == 0) ? colorSkinRoot : vec4(0.0); #ifdef USE_WORLD_CLIP_PLANES world_clip_planes_calc_clip_distance(pos_4d.xyz); diff --git a/source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl index 1f3a23324bb..d137286c63e 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl @@ -37,9 +37,9 @@ void main() vec3 ls_cell_location; /* Keep in sync with update_irradiance_probe */ - ls_cell_location.z = float(gl_VertexID % grid_resolution.z); - ls_cell_location.y = float((gl_VertexID / grid_resolution.z) % grid_resolution.y); - ls_cell_location.x = float(gl_VertexID / (grid_resolution.z * grid_resolution.y)); + ls_cell_location.z = float(gl_VertexIndex % grid_resolution.z); + ls_cell_location.y = float((gl_VertexIndex / grid_resolution.z) % grid_resolution.y); + ls_cell_location.x = float(gl_VertexIndex / (grid_resolution.z * grid_resolution.y)); ls_cell_location += 0.5; ls_cell_location /= vec3(grid_resolution); diff --git a/source/blender/draw/engines/overlay/shaders/extra_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_vert.glsl index 59c9d0a665d..a93a5b56e08 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/extra_vert.glsl @@ -225,7 +225,7 @@ void main() /* HACK: to avoid losing sub-pixel object in selections, we add a bit of randomness to the * wire to at least create one fragment that will pass the occlusion query. */ /* TODO(fclem): Limit this workaround to selection. It's not very noticeable but still... */ - gl_Position.xy += sizeViewportInv.xy * gl_Position.w * ((gl_VertexID % 2 == 0) ? -1.0 : 1.0); + gl_Position.xy += sizeViewportInv.xy * gl_Position.w * ((gl_VertexIndex % 2 == 0) ? -1.0 : 1.0); #endif #ifdef USE_WORLD_CLIP_PLANES diff --git a/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl index 91f45329018..d00b9a01f70 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl @@ -21,7 +21,7 @@ void main() /* HACK: to avoid losing sub-pixel object in selections, we add a bit of randomness to the * wire to at least create one fragment that will pass the occlusion query. */ /* TODO(fclem): Limit this workaround to selection. It's not very noticeable but still... */ - gl_Position.xy += sizeViewportInv.xy * gl_Position.w * ((gl_VertexID % 2 == 0) ? -1.0 : 1.0); + gl_Position.xy += sizeViewportInv.xy * gl_Position.w * ((gl_VertexIndex % 2 == 0) ? -1.0 : 1.0); #endif stipple_coord = stipple_start = screen_position(gl_Position); diff --git a/source/blender/draw/engines/overlay/shaders/motion_path_line_vert.glsl b/source/blender/draw/engines/overlay/shaders/motion_path_line_vert.glsl index 7486f287a79..35475905a0e 100644 --- a/source/blender/draw/engines/overlay/shaders/motion_path_line_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/motion_path_line_vert.glsl @@ -28,7 +28,7 @@ void main() ssPos = proj(gl_Position); - int frame = gl_VertexID + cacheStart; + int frame = gl_VertexIndex + cacheStart; float intensity; /* how faint */ diff --git a/source/blender/draw/engines/overlay/shaders/motion_path_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/motion_path_point_vert.glsl index 14335eb1b99..8fd89414aea 100644 --- a/source/blender/draw/engines/overlay/shaders/motion_path_point_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/motion_path_point_vert.glsl @@ -21,14 +21,14 @@ void main() gl_Position = ViewProjectionMatrix * vec4(pos, 1.0); gl_PointSize = float(pointSize + 2); - int frame = gl_VertexID + cacheStart; + int frame = gl_VertexIndex + cacheStart; bool use_custom_color = customColor.x >= 0.0; finalColor = (use_custom_color) ? vec4(customColor, 1.0) : vec4(1.0); /* Bias to reduce z fighting with the path */ gl_Position.z -= 1e-4; - if (gl_VertexID % stepSize == 0) { + if (gl_VertexIndex % stepSize == 0) { gl_PointSize = float(pointSize) + 4; } diff --git a/source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl b/source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl index f714646fe40..243c900b5a7 100644 --- a/source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl @@ -61,7 +61,7 @@ vec4 flag_to_color(uint flag) void main() { - int cell = gl_VertexID / 8; + int cell = gl_VertexIndex / 8; mat3 rot_mat = mat3(0.0); vec3 cell_offset = vec3(0.5); @@ -113,7 +113,7 @@ void main() #endif vec3 pos = domainOriginOffset + cellSize * (vec3(cell_co + adaptiveCellOffset) + cell_offset); - vec3 rotated_pos = rot_mat * corners[indices[gl_VertexID % 8]]; + vec3 rotated_pos = rot_mat * corners[indices[gl_VertexIndex % 8]]; pos += rotated_pos * cellSize; vec3 world_pos = point_object_to_world(pos); diff --git a/source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl b/source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl index 174b31b6816..7ed93033682 100644 --- a/source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl @@ -118,11 +118,11 @@ vec3 get_vector_mac(ivec3 cell_co) void main() { #ifdef USE_NEEDLE - int cell = gl_VertexID / 12; + int cell = gl_VertexIndex / 12; #elif defined(USE_MAC) - int cell = gl_VertexID / 6; + int cell = gl_VertexIndex / 6; #else - int cell = gl_VertexID / 2; + int cell = gl_VertexIndex / 2; #endif ivec3 volume_size = textureSize(velocityX, 0); @@ -156,7 +156,7 @@ void main() vec3 color; vector = (isCellCentered) ? get_vector_mac(cell_co) : get_vector(cell_co); - switch (gl_VertexID % 6) { + switch (gl_VertexIndex % 6) { case 0: /* Tail of X component. */ pos.x += (drawMACX) ? -0.5 * cellSize.x : 0.0; color = vec3(1.0, 0.0, 0.0); /* red */ @@ -201,12 +201,12 @@ void main() mat3 rot_mat = rotation_from_vector(vector); # ifdef USE_NEEDLE - vec3 rotated_pos = rot_mat * corners[indices[gl_VertexID % 12]]; + vec3 rotated_pos = rot_mat * corners[indices[gl_VertexIndex % 12]]; pos += rotated_pos * vector_length * displaySize * cellSize; # else vec3 rotated_pos = rot_mat * vec3(0.0, 0.0, 1.0); - pos += ((gl_VertexID % 2) == 1) ? rotated_pos * vector_length * displaySize * cellSize : - vec3(0.0); + pos += ((gl_VertexIndex % 2) == 1) ? rotated_pos * vector_length * displaySize * cellSize : + vec3(0.0); # endif #endif diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl index 060b7a957c1..fa32ef9e31b 100644 --- a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl @@ -156,7 +156,7 @@ void main() #ifdef SELECT_EDGES /* HACK: to avoid losing sub-pixel object in selections, we add a bit of randomness to the * wire to at least create one fragment that will pass the occlusion query. */ - gl_Position.xy += sizeViewportInv.xy * gl_Position.w * ((gl_VertexID % 2 == 0) ? -1.0 : 1.0); + gl_Position.xy += sizeViewportInv.xy * gl_Position.w * ((gl_VertexIndex % 2 == 0) ? -1.0 : 1.0); #endif #ifdef USE_WORLD_CLIP_PLANES diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl index 07734d19972..31eda3670e9 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl @@ -5,7 +5,7 @@ out vec4 offset[3]; void main() { - int v = gl_VertexID % 3; + int v = gl_VertexIndex % 3; float x = -1.0 + float((v & 1) << 2); float y = -1.0 + float((v & 2) << 1); gl_Position = vec4(x, y, 1.0, 1.0); diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index 220a7f37c3d..205feba7eb1 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -22,6 +22,12 @@ #pragma once +#include "BKE_mesh_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + struct GPUBatch; struct GPUIndexBuf; struct GPUMaterial; @@ -41,12 +47,6 @@ struct PointCloud; struct Volume; struct bGPdata; -#include "BKE_mesh_types.h" - -#ifdef __cplusplus -extern "C" { -#endif - /* Expose via BKE callbacks */ void DRW_mball_batch_cache_dirty_tag(struct MetaBall *mb, int mode); void DRW_mball_batch_cache_validate(struct MetaBall *mb); diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 1d9bc607590..8f2727cc751 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -3108,7 +3108,7 @@ void DRW_opengl_context_create(void) DST.gl_context = WM_opengl_context_create(); WM_opengl_context_activate(DST.gl_context); /* Be sure to create gpu_context too. */ - DST.gpu_context = GPU_context_create(NULL); + DST.gpu_context = GPU_context_create(NULL, DST.gl_context); /* So we activate the window's one afterwards. */ wm_window_reset_drawable(); } diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index c98ecc8ac00..42d61c881b0 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -1299,6 +1299,7 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader) shgroup, view_ubo_location, DRW_UNIFORM_BLOCK, G_draw.view_ubo, 0, 0, 1); } +#ifndef WITH_VULKAN /* This is needed until we have proper shader interfaces for vulkan. */ /* Not supported. */ BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW_INV) == -1); BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW) == -1); @@ -1311,6 +1312,7 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader) BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_PROJECTION_INV) == -1); BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_CLIPPLANES) == -1); BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MVP) == -1); +#endif } static DRWShadingGroup *drw_shgroup_create_ex(struct GPUShader *shader, DRWPass *pass) diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c index 83d0030f89b..a69a185f3d4 100644 --- a/source/blender/draw/intern/draw_manager_shader.c +++ b/source/blender/draw/intern/draw_manager_shader.c @@ -265,7 +265,7 @@ static void drw_deferred_shader_add(GPUMaterial *mat, bool deferred) } else { comp->gl_context = WM_opengl_context_create(); - comp->gpu_context = GPU_context_create(NULL); + comp->gpu_context = GPU_context_create(NULL, comp->gl_context); GPU_context_active_set(NULL); WM_opengl_context_activate(DST.gl_context); diff --git a/source/blender/draw/intern/shaders/common_fullscreen_vert.glsl b/source/blender/draw/intern/shaders/common_fullscreen_vert.glsl index 8a7fb97d98c..9fdee29cbd9 100644 --- a/source/blender/draw/intern/shaders/common_fullscreen_vert.glsl +++ b/source/blender/draw/intern/shaders/common_fullscreen_vert.glsl @@ -3,7 +3,7 @@ out vec4 uvcoordsvar; void main() { - int v = gl_VertexID % 3; + int v = gl_VertexIndex % 3; float x = -1.0 + float((v & 1) << 2); float y = -1.0 + float((v & 2) << 1); gl_Position = vec4(x, y, 1.0, 1.0); diff --git a/source/blender/draw/intern/shaders/common_hair_lib.glsl b/source/blender/draw/intern/shaders/common_hair_lib.glsl index 6cc7f09a852..20763d70794 100644 --- a/source/blender/draw/intern/shaders/common_hair_lib.glsl +++ b/source/blender/draw/intern/shaders/common_hair_lib.glsl @@ -126,12 +126,12 @@ void hair_get_interp_attrs( int hair_get_strand_id(void) { - return gl_VertexID / (hairStrandsRes * hairThicknessRes); + return gl_VertexIndex / (hairStrandsRes * hairThicknessRes); } int hair_get_base_id(void) { - return gl_VertexID / hairThicknessRes; + return gl_VertexIndex / hairThicknessRes; } /* Copied from cycles. */ @@ -199,7 +199,7 @@ void hair_get_pos_tan_binor_time(bool is_persp, thickness = hair_shaperadius(hairRadShape, hairRadRoot, hairRadTip, time); if (hairThicknessRes > 1) { - thick_time = float(gl_VertexID % hairThicknessRes) / float(hairThicknessRes - 1); + thick_time = float(gl_VertexIndex % hairThicknessRes) / float(hairThicknessRes - 1); thick_time = thickness * (thick_time * 2.0 - 1.0); /* Take object scale into account. diff --git a/source/blender/draw/intern/shaders/common_hair_refine_vert.glsl b/source/blender/draw/intern/shaders/common_hair_refine_vert.glsl index 371d43827b9..151bdf69032 100644 --- a/source/blender/draw/intern/shaders/common_hair_refine_vert.glsl +++ b/source/blender/draw/intern/shaders/common_hair_refine_vert.glsl @@ -19,7 +19,7 @@ void main(void) finalColor = hair_interp_data(data0, data1, data2, data3, weights); #ifdef TF_WORKAROUND - int id = gl_VertexID - idOffset; + int id = gl_VertexIndex - idOffset; gl_Position.x = ((float(id % targetWidth) + 0.5) / float(targetWidth)) * 2.0 - 1.0; gl_Position.y = ((float(id / targetWidth) + 0.5) / float(targetHeight)) * 2.0 - 1.0; gl_Position.z = 0.0; diff --git a/source/blender/draw/intern/shaders/common_view_lib.glsl b/source/blender/draw/intern/shaders/common_view_lib.glsl index a980b87821a..269be150fb7 100644 --- a/source/blender/draw/intern/shaders/common_view_lib.glsl +++ b/source/blender/draw/intern/shaders/common_view_lib.glsl @@ -201,10 +201,10 @@ uniform mat4 ModelMatrixInverse; #define point_world_to_object(p) ((ModelMatrixInverse * vec4(p, 1.0)).xyz) #define point_world_to_view(p) ((ViewMatrix * vec4(p, 1.0)).xyz) -/* Due to some shader compiler bug, we somewhat need to access gl_VertexID +/* Due to some shader compiler bug, we somewhat need to access gl_VertexIndex * to make vertex shaders work. even if it's actually dead code. */ #ifdef GPU_INTEL -# define GPU_INTEL_VERTEX_SHADER_WORKAROUND gl_Position.x = float(gl_VertexID); +# define GPU_INTEL_VERTEX_SHADER_WORKAROUND gl_Position.x = float(gl_VertexIndex); #else # define GPU_INTEL_VERTEX_SHADER_WORKAROUND #endif diff --git a/source/blender/draw/tests/draw_testing.cc b/source/blender/draw/tests/draw_testing.cc index 45a857e7577..5087e7e494d 100644 --- a/source/blender/draw/tests/draw_testing.cc +++ b/source/blender/draw/tests/draw_testing.cc @@ -4,6 +4,12 @@ #include "GPU_shader.h" +#include "IMB_imbuf.h" + +#include "BKE_appdir.h" +#include "BKE_idtype.h" + +#include "DRW_engine.h" #include "draw_manager_testing.h" namespace blender::draw { @@ -12,7 +18,25 @@ namespace blender::draw { void DrawOpenGLTest::SetUp() { GPUOpenGLTest::SetUp(); + + /* Initialize color management. Required to construct a scene creation depends on it. */ + BKE_idtype_init(); + BKE_appdir_init(); + IMB_init(); + + DRW_engines_register(); + DRW_draw_state_init_gtests(GPU_SHADER_CFG_DEFAULT); } +void DrawOpenGLTest::TearDown() +{ + DRW_engines_free(); + + IMB_exit(); + BKE_appdir_exit(); + + GPUTest::TearDown(); +} + } // namespace blender::draw diff --git a/source/blender/draw/tests/draw_testing.hh b/source/blender/draw/tests/draw_testing.hh index 00f0ac5bab7..74712c10d49 100644 --- a/source/blender/draw/tests/draw_testing.hh +++ b/source/blender/draw/tests/draw_testing.hh @@ -8,6 +8,7 @@ namespace blender::draw { class DrawOpenGLTest : public blender::gpu::GPUOpenGLTest { public: void SetUp() override; + void TearDown() override; }; #define DRAW_TEST(test_name) \ diff --git a/source/blender/draw/tests/performance_test.cc b/source/blender/draw/tests/performance_test.cc new file mode 100644 index 00000000000..6d22039e907 --- /dev/null +++ b/source/blender/draw/tests/performance_test.cc @@ -0,0 +1,223 @@ +/* Apache License, Version 2.0 */ + +#include "testing/testing.h" + +#include "draw_testing.hh" +#include "intern/draw_manager_testing.h" + +#include "DRW_engine.h" +#include "draw_cache_impl.h" + +#include "BKE_editmesh.h" +#include "BKE_idtype.h" +#include "BKE_mesh.h" +#include "BKE_mesh_wrapper.h" +#include "BKE_scene.h" + +#include "BLI_rand.hh" +#include "BLI_task.h" + +#include "ED_mesh.h" + +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "GPU_context.h" +#include "GPU_init_exit.h" +#include "GPU_shader.h" + +#include "engines/eevee/eevee_private.h" +#include "engines/gpencil/gpencil_engine.h" +#include "engines/image/image_private.hh" +#include "engines/overlay/overlay_private.h" +#include "engines/workbench/workbench_private.h" + +namespace blender::draw { + +/** + * During investigation or executing in a profiler it is handly to disable multithreading. This can + * be done by setting RUN_SINGLE_THREADED to true. + * + * Default(false) => run multithreaded + */ +constexpr bool RUN_SINGLE_THREADED = false; + +class DrawCacheTest : public DrawOpenGLTest { + protected: + TaskGraph *task_graph; + + public: + void SetUp() override + { + DrawOpenGLTest::SetUp(); + if (RUN_SINGLE_THREADED) { + BLI_system_num_threads_override_set(1); + } + task_graph = BLI_task_graph_create(); + } + + void TearDown() override + { + BLI_task_graph_free(task_graph); + if (RUN_SINGLE_THREADED) { + BLI_system_num_threads_override_set(0); + } + DrawOpenGLTest::TearDown(); + } +}; + +class DrawCachePerformanceTest : public DrawCacheTest { + protected: + Scene scene = {{nullptr}}; + Object ob_mesh = {{nullptr}}; + Mesh mesh = {{nullptr}}; + BMesh *bm = nullptr; + RandomNumberGenerator rng; + + public: + void SetUp() override + { + DrawCacheTest::SetUp(); + IDType_ID_SCE.init_data(&scene.id); + IDType_ID_OB.init_data(&ob_mesh.id); + IDType_ID_ME.init_data(&mesh.id); + ob_mesh.type = OB_MESH; + ob_mesh.data = &mesh; + EDBM_mesh_make(&ob_mesh, SCE_SELECT_VERTEX, false); + bm = mesh.edit_mesh->bm; + + /* Ensure batch cache is available. */ + DRW_mesh_batch_cache_validate(&mesh); + } + + void TearDown() override + { + EDBM_mesh_free_data(mesh.edit_mesh); + bm = nullptr; + IDType_ID_ME.free_data(&mesh.id); + IDType_ID_OB.free_data(&ob_mesh.id); + IDType_ID_SCE.free_data(&scene.id); + DrawCacheTest::TearDown(); + } + + protected: + /** + * Build a test mesh with given number of polygons. + * Each polygon is created from 3 random generated verts. + */ + void build_mesh(size_t num_polygons) + { + add_polygons_to_bm(num_polygons); + + /* Make sure mesh_eval_final is up to date (inline depsgraph evaluation). See + * `editbmesh_calc_modifiers`. */ + mesh.edit_mesh->mesh_eval_final = BKE_mesh_from_bmesh_for_eval_nomain( + mesh.edit_mesh->bm, nullptr, &mesh); + mesh.edit_mesh->mesh_eval_cage = BKE_mesh_wrapper_from_editmesh_with_coords( + mesh.edit_mesh, nullptr, nullptr, &mesh); + + BKE_editmesh_looptri_calc(mesh.edit_mesh); + } + + /** + * Check if the given GPUBatch is filled. + */ + void expect_filled(GPUBatch *batch) + { + EXPECT_NE(batch->elem, nullptr); + } + + /** + * Check if the given GPUBatch is filled. + */ + void expect_empty(GPUBatch *batch) + { + EXPECT_EQ(batch->elem, nullptr); + for (int i = 0; i < GPU_BATCH_VBO_MAX_LEN; i++) { + EXPECT_EQ(batch->verts[i], nullptr); + } + } + + private: + /** + * Create a new random vert in BMesh. + */ + BMVert *add_random_vert_to_bm() + { + float co[3] = {(rng.get_float() - 0.5f) * 10.0f, + (rng.get_float() - 0.5f) * 10.0f, + (rng.get_float() - 0.5f) * 10.0f}; + BMVert *result = BM_vert_create(bm, co, nullptr, BM_CREATE_NOP); + return result; + } + + /** + * Add `num_polygons` polygons to the BMesh. + */ + void add_polygons_to_bm(size_t num_polygons) + { + /* Use 3 verts per face to skip triangulation. */ + const int verts_per_face = 3; + + for (int i = 0; i < num_polygons; i++) { + BMVert *verts[verts_per_face]; + for (int j = 0; j < verts_per_face; j++) { + verts[j] = add_random_vert_to_bm(); + } + BM_face_create_verts(bm, verts, verts_per_face, nullptr, BM_CREATE_NOP, true); + } + } +}; + +/** + * Base line benchmark simulating edit mesh vertice transform of a large mesh. + * + * In Blender 2.93 the whole cache would be freed so the baseline is to recalculate + * all needed caches. + */ +TEST_F(DrawCachePerformanceTest, edit_mesh_performance_baseline_293) +{ + /* Approximates a subdivided cube 7 times in faces. */ + const int num_polygons = 100000; + const int num_benchmark_loops = 32; + /* Create a bmesh object in edit mode. */ + build_mesh(num_polygons); + + for (int i = 0; i < num_benchmark_loops; i++) { + /* Invalidate caches. + * In reality the mesh gets a copy on write signal and frees the cache (mesh_data_free). */ + BKE_mesh_batch_cache_dirty_tag_cb(&mesh, BKE_MESH_BATCH_DIRTY_ALL); + DRW_mesh_batch_cache_validate(&mesh); + + /* Request caches. */ + GPUBatch *batch_triangles = DRW_mesh_batch_cache_get_edit_triangles(&mesh); + GPUBatch *batch_vertices = DRW_mesh_batch_cache_get_edit_vertices(&mesh); + GPUBatch *batch_edges = DRW_mesh_batch_cache_get_edit_edges(&mesh); + GPUBatch *batch_vnors = DRW_mesh_batch_cache_get_edit_vnors(&mesh); + GPUBatch *batch_lnors = DRW_mesh_batch_cache_get_edit_lnors(&mesh); + GPUBatch *batch_facedots = DRW_mesh_batch_cache_get_edit_facedots(&mesh); + + /* Check if caches are empty. */ + expect_empty(batch_triangles); + expect_empty(batch_vertices); + expect_empty(batch_edges); + expect_empty(batch_vnors); + expect_empty(batch_lnors); + expect_empty(batch_facedots); + + /* Update caches. */ + DRW_mesh_batch_cache_create_requested(task_graph, &ob_mesh, &mesh, &scene, false, true); + BLI_task_graph_work_and_wait(task_graph); + + /* Check if caches are filled. */ + expect_filled(batch_triangles); + expect_filled(batch_vertices); + expect_filled(batch_edges); + expect_filled(batch_vnors); + expect_filled(batch_lnors); + expect_filled(batch_facedots); + } +} + +} // namespace blender::draw diff --git a/source/blender/draw/tests/shaders_test.cc b/source/blender/draw/tests/shaders_test.cc index ef702821a59..e955e2edf62 100644 --- a/source/blender/draw/tests/shaders_test.cc +++ b/source/blender/draw/tests/shaders_test.cc @@ -162,6 +162,7 @@ DRAW_TEST(workbench_glsl_shaders) static void test_gpencil_glsl_shaders() { + EXPECT_NE(GPENCIL_shader_antialiasing(0), nullptr); EXPECT_NE(GPENCIL_shader_antialiasing(1), nullptr); EXPECT_NE(GPENCIL_shader_antialiasing(2), nullptr); @@ -185,6 +186,7 @@ DRAW_TEST(gpencil_glsl_shaders) static void test_image_glsl_shaders() { + IMAGE_shader_library_ensure(); EXPECT_NE(IMAGE_shader_image_get(false), nullptr); @@ -289,7 +291,7 @@ static void test_overlay_glsl_shaders() } DRAW_TEST(overlay_glsl_shaders) -static void test_eevee_glsl_shaders_static() +static void test_eevee_glsl_shaders() { EEVEE_shaders_material_shaders_init(); @@ -378,7 +380,7 @@ static void test_eevee_glsl_shaders_static() EXPECT_NE(EEVEE_shaders_effect_reflection_resolve_sh_get(), nullptr); EEVEE_shaders_free(); } -DRAW_TEST(eevee_glsl_shaders_static) +DRAW_TEST(eevee_glsl_shaders) static void test_draw_shaders(eParticleRefineShaderType sh_type) { diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 4868096e594..e7b543ef8f3 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -30,6 +30,7 @@ set(INC . intern opengl + vulkan ../blenkernel ../blenlib ../bmesh @@ -191,6 +192,49 @@ set(LIB ${BLENDER_GL_LIBRARIES} ) +if(WITH_VULKAN) + list(APPEND INC_SYS + ${Vulkan_INCLUDE_DIRS} + ) + + list(APPEND LIB + extern_vulkan_memory_allocator + bf_intern_shadercompiler + ${SHADERC_LIBRARIES} + ) + + list(APPEND INC + ../../../extern/vulkan_memory_allocator + ../../../intern/shader_compiler + + ) + + list(APPEND SRC + vulkan/vk_backend.cc + vulkan/vk_context.cc + vulkan/vk_framebuffer.cc + vulkan/vk_texture.cc + vulkan/vk_shader_log.cc + vulkan/vk_shader.cc + + vulkan/vk_backend.hh + vulkan/vk_batch.hh + vulkan/vk_context.hh + vulkan/vk_drawlist.hh + vulkan/vk_framebuffer.hh + vulkan/vk_immediate.hh + vulkan/vk_index_buffer.hh + vulkan/vk_primitive.hh + vulkan/vk_query.hh + vulkan/vk_shader_interface.hh + vulkan/vk_shader.hh + vulkan/vk_state.hh + vulkan/vk_texture.hh + vulkan/vk_uniform_buffer.hh + vulkan/vk_vertex_buffer.hh + ) +endif() + if(NOT WITH_SYSTEM_GLEW) list(APPEND LIB ${BLENDER_GLEW_LIBRARIES} @@ -391,6 +435,12 @@ endif() blender_add_lib(bf_gpu "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") +if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang") + target_compile_options(bf_gpu + PRIVATE "-Wno-nullability-completeness" + ) +endif() + if(CXX_WARN_NO_SUGGEST_OVERRIDE) target_compile_options(bf_gpu PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-Wsuggest-override>) endif() @@ -399,8 +449,8 @@ if(WITH_GTESTS) if(WITH_OPENGL_DRAW_TESTS) set(TEST_SRC tests/gpu_testing.cc - tests/gpu_index_buffer_test.cc + tests/gpu_shader_compiler_test.cc tests/gpu_shader_builtin_test.cc tests/gpu_shader_test.cc @@ -408,10 +458,11 @@ if(WITH_GTESTS) ) set(TEST_INC "../../../intern/ghost/" + "../../../intern/shader_compiler/" ) set(TEST_LIB - ) + include(GTestTesting) blender_add_test_lib(bf_gpu_tests "${TEST_SRC}" "${INC};${TEST_INC}" "${INC_SYS}" "${LIB};${TEST_LIB}") endif() diff --git a/source/blender/gpu/GPU_context.h b/source/blender/gpu/GPU_context.h index 82f13424502..9939f844ff8 100644 --- a/source/blender/gpu/GPU_context.h +++ b/source/blender/gpu/GPU_context.h @@ -35,15 +35,20 @@ extern "C" { typedef enum eGPUBackendType { GPU_BACKEND_NONE = 0, GPU_BACKEND_OPENGL, +#ifdef WITH_VULKAN + GPU_BACKEND_VULKAN, +#endif } eGPUBackendType; -void GPU_backend_init(eGPUBackendType backend); +void GPU_backend_create(eGPUBackendType backend); void GPU_backend_exit(void); /** Opaque type hiding blender::gpu::Context. */ typedef struct GPUContext GPUContext; -GPUContext *GPU_context_create(void *ghost_window); +/* Only one of them must be set. */ +/* TODO(fclem) clean this mess. */ +GPUContext *GPU_context_create(void *ghost_window, void *ghost_context); void GPU_context_discard(GPUContext *); void GPU_context_active_set(GPUContext *); diff --git a/source/blender/gpu/intern/gpu_backend.hh b/source/blender/gpu/intern/gpu_backend.hh index 73792215569..c0774c3b61e 100644 --- a/source/blender/gpu/intern/gpu_backend.hh +++ b/source/blender/gpu/intern/gpu_backend.hh @@ -46,10 +46,12 @@ class GPUBackend { static GPUBackend *get(void); + virtual void init() = 0; + virtual void samplers_update(void) = 0; virtual void compute_dispatch(int groups_x_len, int groups_y_len, int groups_z_len) = 0; - virtual Context *context_alloc(void *ghost_window) = 0; + virtual Context *context_alloc(void *ghost_window, void *ghost_context) = 0; virtual Batch *batch_alloc(void) = 0; virtual DrawList *drawlist_alloc(int list_length) = 0; diff --git a/source/blender/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc index 943a6151ced..2748dffd95f 100644 --- a/source/blender/gpu/intern/gpu_context.cc +++ b/source/blender/gpu/intern/gpu_context.cc @@ -34,6 +34,8 @@ #include "BLI_assert.h" #include "BLI_utildefines.h" +#include "BKE_global.h" + #include "GPU_context.h" #include "GPU_framebuffer.h" @@ -49,6 +51,11 @@ # include "gl_context.hh" #endif +#ifdef WITH_VULKAN +# include "vk_backend.hh" +# include "vk_context.hh" +#endif + #include <mutex> #include <vector> @@ -96,16 +103,27 @@ Context *Context::get() /* -------------------------------------------------------------------- */ -GPUContext *GPU_context_create(void *ghost_window) +GPUContext *GPU_context_create(void *ghost_window, void *ghost_context) { + bool backend_created = false; if (GPUBackend::get() == nullptr) { - /* TODO: move where it make sense. */ - GPU_backend_init(GPU_BACKEND_OPENGL); + /* FIXME We should get the context type from ghost instead of guessing it. */ + eGPUBackendType type = GPU_BACKEND_OPENGL; +#ifdef WITH_VULKAN + if (G.debug & G_DEBUG_VK_CONTEXT) { + type = GPU_BACKEND_VULKAN; + } +#endif + backend_created = true; + GPU_backend_create(type); } - - Context *ctx = GPUBackend::get()->context_alloc(ghost_window); - + GPUBackend *backend = GPUBackend::get(); + Context *ctx = backend->context_alloc(ghost_window, ghost_context); GPU_context_active_set(wrap(ctx)); + + if (backend_created) { + backend->init(); + } return wrap(ctx); } @@ -164,16 +182,21 @@ void GPU_context_main_unlock(void) static GPUBackend *g_backend; -void GPU_backend_init(eGPUBackendType backend_type) +void GPU_backend_create(eGPUBackendType backend_type) { BLI_assert(g_backend == nullptr); switch (backend_type) { -#if WITH_OPENGL_BACKEND +#ifdef WITH_OPENGL_BACKEND case GPU_BACKEND_OPENGL: g_backend = new GLBackend; break; #endif +#ifdef WITH_VULKAN + case GPU_BACKEND_VULKAN: + g_backend = new VKBackend; + break; +#endif default: BLI_assert(0); break; diff --git a/source/blender/gpu/opengl/gl_backend.hh b/source/blender/gpu/opengl/gl_backend.hh index e9dcdffced0..bb220a699ae 100644 --- a/source/blender/gpu/opengl/gl_backend.hh +++ b/source/blender/gpu/opengl/gl_backend.hh @@ -47,7 +47,14 @@ class GLBackend : public GPUBackend { GLSharedOrphanLists shared_orphan_list_; public: - GLBackend() + ~GLBackend() + { + GLTexture::samplers_free(); + + GLBackend::platform_exit(); + } + + void init() override { /* platform_init needs to go first. */ GLBackend::platform_init(); @@ -55,12 +62,6 @@ class GLBackend : public GPUBackend { GLBackend::capabilities_init(); GLTexture::samplers_init(); } - ~GLBackend() - { - GLTexture::samplers_free(); - - GLBackend::platform_exit(); - } static GLBackend *get(void) { @@ -72,7 +73,7 @@ class GLBackend : public GPUBackend { GLTexture::samplers_update(); }; - Context *context_alloc(void *ghost_window) override + Context *context_alloc(void *ghost_window, void *UNUSED(ghost_context)) override { return new GLContext(ghost_window, shared_orphan_list_); }; diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc index 66a1bd5ceb7..6c9e54608c3 100644 --- a/source/blender/gpu/opengl/gl_shader.cc +++ b/source/blender/gpu/opengl/gl_shader.cc @@ -109,6 +109,9 @@ static char *glsl_patch_default_get() STR_CONCATF(patch, slen, "#define DFDX_SIGN %1.1f\n", GLContext::derivative_signs[0]); STR_CONCATF(patch, slen, "#define DFDY_SIGN %1.1f\n", GLContext::derivative_signs[1]); + /* Converting Vulkan GLSL to OpenGL GLSL. */ + STR_CONCAT(patch, slen, "#define gl_VertexIndex gl_VertexID\n"); + BLI_assert(slen < sizeof(patch)); return patch; } diff --git a/source/blender/gpu/shaders/gpu_shader_2D_area_borders_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_area_borders_vert.glsl index d20ddcd27c0..f85cea69880 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_area_borders_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_area_borders_vert.glsl @@ -11,7 +11,7 @@ out vec2 uv; void main() { - int corner_id = (gl_VertexID / cornerLen) % 4; + int corner_id = (gl_VertexIndex / cornerLen) % 4; vec2 final_pos = pos * scale; diff --git a/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl index bdc0d37a7ae..f76c590e961 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl @@ -19,7 +19,7 @@ void main() vec4 tex = calls_data[gl_InstanceID * 3 + 1]; finalColor = calls_data[gl_InstanceID * 3 + 2]; - /* Use pos to select the right swizzle (instead of gl_VertexID) + /* Use pos to select the right swizzle (instead of gl_VertexIndex) * in order to workaround an OSX driver bug. */ if (pos == vec2(0.0, 0.0)) { rect.xy = rect.xz; diff --git a/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl index ab9c30505c2..d3cca9e0d84 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl @@ -13,15 +13,15 @@ void main() { vec2 uv; vec2 co; - if (gl_VertexID == 0) { + if (gl_VertexIndex == 0) { co = rect_geom.xy; uv = rect_icon.xy; } - else if (gl_VertexID == 1) { + else if (gl_VertexIndex == 1) { co = rect_geom.xw; uv = rect_icon.xw; } - else if (gl_VertexID == 2) { + else if (gl_VertexIndex == 2) { co = rect_geom.zw; uv = rect_icon.zw; } diff --git a/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl index 8325568988c..fb7920972bd 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl @@ -114,7 +114,7 @@ void main(void) float expand_dist = (uv.y * 2.0 - 1.0); colorGradient = expand_dist; - if (gl_VertexID < MID_VERTEX) { + if (gl_VertexIndex < MID_VERTEX) { /* Shadow pass */ finalColor = colShadow; } diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl index b5036b51d9d..2162f3433ce 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl @@ -108,8 +108,8 @@ vec2 do_widget(void) vec2 do_tria() { - int vidx = gl_VertexID % 4; - bool tria2 = gl_VertexID > 7; + int vidx = gl_VertexIndex % 4; + bool tria2 = gl_VertexIndex > 7; vec2 pos; float size = (tria2) ? -tria2Size : tria1Size; @@ -204,7 +204,7 @@ vec2 do_tria() void main() { discardFac = discardFactor; - bool is_tria = (gl_VertexID > 3); + bool is_tria = (gl_VertexIndex > 3); vec2 pos = (is_tria) ? do_tria() : do_widget(); gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); diff --git a/source/blender/gpu/shaders/gpu_shader_text_vert.glsl b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl index 768638e5229..62e9ffde5a2 100644 --- a/source/blender/gpu/shaders/gpu_shader_text_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl @@ -20,8 +20,8 @@ void main() interp_size = int(glyph_size.x < 0) + int(glyph_size.y < 0); /* Quad expension using instanced rendering. */ - float x = float(gl_VertexID % 2); - float y = float(gl_VertexID / 2); + float x = float(gl_VertexIndex % 2); + float y = float(gl_VertexIndex / 2); vec2 quad = vec2(x, y); vec2 interp_offset = float(interp_size) / abs(pos.zw - pos.xy); diff --git a/source/blender/gpu/tests/gpu_shader_builtin_test.cc b/source/blender/gpu/tests/gpu_shader_builtin_test.cc index 523a7e5b881..dfb1f6bad2a 100644 --- a/source/blender/gpu/tests/gpu_shader_builtin_test.cc +++ b/source/blender/gpu/tests/gpu_shader_builtin_test.cc @@ -88,7 +88,6 @@ static void test_shader_builtin() test_compile_builtin_shader(GPU_SHADER_2D_UV_FACES_STRETCH_AREA, GPU_SHADER_CFG_DEFAULT); test_compile_builtin_shader(GPU_SHADER_2D_UV_FACES_STRETCH_ANGLE, GPU_SHADER_CFG_DEFAULT); } - GPU_TEST(shader_builtin) } // namespace blender::gpu::tests diff --git a/source/blender/gpu/tests/gpu_shader_compiler_test.cc b/source/blender/gpu/tests/gpu_shader_compiler_test.cc new file mode 100644 index 00000000000..37eb4608cb6 --- /dev/null +++ b/source/blender/gpu/tests/gpu_shader_compiler_test.cc @@ -0,0 +1,29 @@ +/* Apache License, Version 2.0 */ + +#include "gpu_testing.hh" +#include "shader_compiler.hh" + +namespace blender::gpu::tests { + +#ifdef WITH_VULKAN +TEST_F(GPUVulkanTest, shader_compiler) +{ + std::string source = "#version 450\nvoid main() {}"; + shader_compiler::Compiler *compiler = shader_compiler::Compiler::create_default(); + shader_compiler::Job job; + job.source = source; + job.name = __func__; + job.source_type = shader_compiler::SourceType::GlslComputeShader; + job.compilation_target = shader_compiler::TargetType::SpirV; + + shader_compiler::Result *result = compiler->compile(job); + EXPECT_EQ(result->type, shader_compiler::TargetType::SpirV); + EXPECT_EQ(result->status_code, shader_compiler::StatusCode::Ok); + EXPECT_GT(result->bin.size(), 0); + EXPECT_EQ(result->error_log, ""); + delete result; + delete compiler; +} +#endif + +} // namespace blender::gpu::tests
\ No newline at end of file diff --git a/source/blender/gpu/tests/gpu_testing.cc b/source/blender/gpu/tests/gpu_testing.cc index 7fd473069c2..0f8ef02d9ed 100644 --- a/source/blender/gpu/tests/gpu_testing.cc +++ b/source/blender/gpu/tests/gpu_testing.cc @@ -2,6 +2,7 @@ #include "testing/testing.h" +#include "BKE_global.h" #include "CLG_log.h" #include "GPU_context.h" @@ -17,9 +18,9 @@ void GPUTest::SetUp() GHOST_GLSettings glSettings = {0}; CLG_init(); ghost_system = GHOST_CreateSystem(); - ghost_context = GHOST_CreateOpenGLContext(ghost_system, glSettings); + ghost_context = GHOST_CreateOpenGLContext(ghost_system, draw_context_type, glSettings); GHOST_ActivateOpenGLContext(ghost_context); - context = GPU_context_create(nullptr); + context = GPU_context_create(NULL, ghost_context); GPU_init(); } diff --git a/source/blender/gpu/tests/gpu_testing.hh b/source/blender/gpu/tests/gpu_testing.hh index c45770cb94e..cd13eb85bd1 100644 --- a/source/blender/gpu/tests/gpu_testing.hh +++ b/source/blender/gpu/tests/gpu_testing.hh @@ -2,6 +2,8 @@ #include "GHOST_C-api.h" +#include "BKE_global.h" + struct GPUContext; namespace blender::gpu { @@ -33,13 +35,42 @@ class GPUOpenGLTest : public GPUTest { public: GPUOpenGLTest() : GPUTest(GHOST_kDrawingContextTypeOpenGL) { + G.debug &= ~G_DEBUG_VK_CONTEXT; } }; -#define GPU_TEST(test_name) \ - TEST_F(GPUOpenGLTest, test_name) \ - { \ - test_##test_name(); \ +#ifdef WITH_VULKAN + +class GPUVulkanTest : public GPUTest { + public: + GPUVulkanTest() : GPUTest(GHOST_kDrawingContextTypeVulkan) + { + G.debug |= G_DEBUG_VK_CONTEXT; } +}; + +#endif + +#ifdef WITH_VULKAN + +# define GPU_TEST(test_name) \ + TEST_F(GPUOpenGLTest, test_name) \ + { \ + test_##test_name(); \ + } \ + TEST_F(GPUVulkanTest, test_name) \ + { \ + test_##test_name(); \ + } + +#else /* WITH_VULKAN */ + +# define GPU_TEST(test_name) \ + TEST_F(GPUOpenGLTest, test_name) \ + { \ + test_##test_name(); \ + } + +#endif /* WITH_VULKAN */ } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_backend.cc b/source/blender/gpu/vulkan/vk_backend.cc new file mode 100644 index 00000000000..1c75e0dc193 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_backend.cc @@ -0,0 +1,142 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2020, Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#include "BKE_global.h" + +#include "gpu_capabilities_private.hh" +#include "gpu_platform_private.hh" + +#include "vk_backend.hh" + +namespace blender::gpu { + +/* -------------------------------------------------------------------- */ +/** \name Platform + * \{ */ + +static std::string api_version_get(VkPhysicalDeviceProperties &properties) +{ + uint32_t major = VK_VERSION_MAJOR(properties.driverVersion); + uint32_t minor = VK_VERSION_MINOR(properties.driverVersion); + uint32_t patch = VK_VERSION_PATCH(properties.driverVersion); + + std::stringstream version; + version << major << "." << minor << "." << patch; + return version.str(); +} + +enum class VendorID : uint32_t { + AMD = 0x1002, + Intel = 0x1F96, + NVIDIA = 0x10de, +}; +static constexpr StringRef VENDOR_NAME_AMD = "Advanced Micro Devices"; +static constexpr StringRef VENDOR_NAME_INTEL = "Intel"; +static constexpr StringRef VENDOR_NAME_NVIDIA = "NVIDIA"; +static constexpr StringRef VENDOR_NAME_UNKNOWN = "Unknown"; + +static constexpr StringRef vendor_name_get(VendorID vendor_id) +{ + switch (vendor_id) { + case VendorID::AMD: + return VENDOR_NAME_AMD; + case VendorID::Intel: + return VENDOR_NAME_INTEL; + case VendorID::NVIDIA: + return VENDOR_NAME_NVIDIA; + } + return VENDOR_NAME_UNKNOWN; +} + +static VendorID vendor_id_get(VkPhysicalDeviceProperties &properties) +{ + return static_cast<VendorID>(properties.vendorID); +} + +void VKBackend::platform_init(void) +{ + BLI_assert(!GPG.initialized); + + VKContext *context = VKContext::get(); + VkPhysicalDeviceProperties physical_device_properties; + VkPhysicalDevice physical_device = context->physical_device_get(); + vkGetPhysicalDeviceProperties(physical_device, &physical_device_properties); + const VendorID vendor_id = vendor_id_get(physical_device_properties); + const std::string vendor = vendor_name_get(vendor_id); + const std::string renderer = physical_device_properties.deviceName; + const std::string version = api_version_get(physical_device_properties).c_str(); + eGPUDeviceType device = GPU_DEVICE_ANY; + eGPUOSType os = GPU_OS_ANY; + eGPUDriverType driver = GPU_DRIVER_ANY; + eGPUSupportLevel support_level = GPU_SUPPORT_LEVEL_SUPPORTED; + +#ifdef _WIN32 + os = GPU_OS_WIN; +#elif defined(__APPLE__) + os = GPU_OS_MAC; +#else + os = GPU_OS_UNIX; +#endif + + /* TODO(jbakker): extract the driver type. */ + if (vendor_id == VendorID::AMD) { + device = GPU_DEVICE_ATI; + } + else if (vendor_id == VendorID::Intel) { + device = GPU_DEVICE_INTEL; + } + else if (vendor_id == VendorID::NVIDIA) { + device = GPU_DEVICE_NVIDIA; + } + + GPG.init(device, os, driver, support_level, vendor.c_str(), renderer.c_str(), version.c_str()); +} + +void VKBackend::platform_exit(void) +{ + BLI_assert(GPG.initialized); + GPG.clear(); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Capabilities + * \{ */ + +void VKBackend::capabilities_init(void) +{ + /* Common Capabilities. */ + GCaps.max_texture_size = 2048; + GCaps.max_texture_layers = 64; + GCaps.max_textures_frag = 16; + GCaps.max_textures_vert = 16; + GCaps.max_textures_geom = 16; + GCaps.max_textures = 46; + GCaps.mem_stats_support = false; + GCaps.shader_image_load_store_support = false; +} + +/** \} */ + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_backend.hh b/source/blender/gpu/vulkan/vk_backend.hh new file mode 100644 index 00000000000..d189f7158e7 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_backend.hh @@ -0,0 +1,123 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2020, Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_backend.hh" + +#include "vk_batch.hh" +#include "vk_context.hh" +#include "vk_drawlist.hh" +#include "vk_framebuffer.hh" +#include "vk_index_buffer.hh" +#include "vk_query.hh" +#include "vk_shader.hh" +#include "vk_texture.hh" +#include "vk_uniform_buffer.hh" +#include "vk_vertex_buffer.hh" + +namespace blender { +namespace gpu { + +class VKBackend : public GPUBackend { + public: + ~VKBackend() + { + VKBackend::platform_exit(); + } + + void init() override + { + /* platform_init needs to go first. */ + VKBackend::platform_init(); + + VKBackend::capabilities_init(); + } + + static VKBackend *get(void) + { + return static_cast<VKBackend *>(GPUBackend::get()); + }; + + void samplers_update(void) override{}; + void compute_dispatch(int groups_x_len, int groups_y_len, int groups_z_len) override{}; + + Context *context_alloc(void *ghost_window, void *ghost_context) override + { + return new VKContext(ghost_window, ghost_context); + }; + + Batch *batch_alloc(void) override + { + return new VKBatch(); + }; + + DrawList *drawlist_alloc(int list_length) override + { + return new VKDrawList(list_length); + }; + + FrameBuffer *framebuffer_alloc(const char *name) override + { + return new VKFrameBuffer(name); + }; + + IndexBuf *indexbuf_alloc(void) override + { + return new VKIndexBuf(); + }; + + QueryPool *querypool_alloc(void) override + { + return new VKQueryPool(); + }; + + Shader *shader_alloc(const char *name) override + { + return new VKShader(name); + }; + + Texture *texture_alloc(const char *name) override + { + return new VKTexture(name); + }; + + UniformBuf *uniformbuf_alloc(int size, const char *name) override + { + return new VKUniformBuf(size, name); + }; + + VertBuf *vertbuf_alloc(void) override + { + return new VKVertBuf(); + }; + + private: + static void platform_init(void); + static void platform_exit(void); + + static void capabilities_init(void); +}; + +} // namespace gpu +} // namespace blender diff --git a/source/blender/gpu/vulkan/vk_batch.hh b/source/blender/gpu/vulkan/vk_batch.hh new file mode 100644 index 00000000000..84be5a91b0b --- /dev/null +++ b/source/blender/gpu/vulkan/vk_batch.hh @@ -0,0 +1,64 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2020, Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * GPU geometry batch + * Contains VAOs + VBOs + Shader representing a drawable entity. + */ + +#pragma once + +#include "MEM_guardedalloc.h" + +#include "gpu_batch_private.hh" + +#include "vk_index_buffer.hh" +#include "vk_vertex_buffer.hh" + +namespace blender { +namespace gpu { + +class VKBatch : public Batch { + public: + VKBatch(){}; + ~VKBatch(){}; + + void draw(int v_first, int v_count, int i_first, int i_count) override{}; + + /* Convenience getters. */ + VKIndexBuf *elem_(void) const + { + return static_cast<VKIndexBuf *>(unwrap(elem)); + } + VKVertBuf *verts_(const int index) const + { + return static_cast<VKVertBuf *>(unwrap(verts[index])); + } + VKVertBuf *inst_(const int index) const + { + return static_cast<VKVertBuf *>(unwrap(inst[index])); + } + + MEM_CXX_CLASS_ALLOC_FUNCS("VKBatch"); +}; + +} // namespace gpu +} // namespace blender diff --git a/source/blender/gpu/vulkan/vk_context.cc b/source/blender/gpu/vulkan/vk_context.cc new file mode 100644 index 00000000000..c19a68cd4f4 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_context.cc @@ -0,0 +1,164 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2020, Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#include "GHOST_C-api.h" + +#include "vk_framebuffer.hh" +#include "vk_immediate.hh" +#include "vk_state.hh" + +#include "vk_context.hh" + +namespace blender::gpu { + +/* -------------------------------------------------------------------- */ +/** \name Constructor / Destructor + * \{ */ + +VKContext::VKContext(void *ghost_window, void *ghost_context) +{ + ghost_window_ = ghost_window; + + if (ghost_window != nullptr) { + ghost_context = GHOST_GetDrawingContext((GHOST_WindowHandle)ghost_window); + } + + state_manager = new VKStateManager(); + imm = new VKImmediate(); + + GHOST_GetVulkanHandles((GHOST_ContextHandle)ghost_context, + &instance_, + &physical_device_, + &device_, + &graphic_queue_familly_); + + vkGetDeviceQueue(device_, graphic_queue_familly_, 0, &graphic_queue_); + + { + VkCommandPoolCreateInfo info = {VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO}; + info.queueFamilyIndex = graphic_queue_familly_; + vkCreateCommandPool(device_, &info, nullptr, &graphic_cmd_pool_); + } + + /* For offscreen contexts. Default framebuffer is empty. */ + active_fb = back_left = new VKFrameBuffer("back_left"); + + { + VmaAllocatorCreateInfo info = {}; + /* TODO use same vulkan version as GHOST. */ + info.vulkanApiVersion = VK_API_VERSION_1_0; + info.physicalDevice = physical_device_; + info.device = device_; + info.instance = instance_; + vmaCreateAllocator(&info, &mem_allocator_); + } +} + +VKContext::~VKContext() +{ + vkDestroyCommandPool(device_, graphic_cmd_pool_, nullptr); + vmaDestroyAllocator(mem_allocator_); +} + +void VKContext::activate() +{ + if (ghost_window_) { + VkImage image; /* TODO will be used for reading later... */ + VkFramebuffer framebuffer; + VkCommandBuffer command_buffer; + VkRenderPass render_pass; + VkExtent2D extent; + uint32_t fb_id; + + GHOST_GetVulkanBackbuffer((GHOST_WindowHandle)ghost_window_, + &image, + &framebuffer, + &command_buffer, + &render_pass, + &extent, + &fb_id); + + if (fb_id != fb_id_) { + /* Recreate the gpu::VKFrameBuffer wrapper after every swap. */ + delete back_left; + } + + back_left = new VKFrameBuffer("back_left", framebuffer, command_buffer, render_pass, extent); + active_fb = back_left; + } + + immActivate(); +} + +void VKContext::deactivate() +{ + immDeactivate(); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Command buffers + * \{ */ + +VkCommandBuffer VKContext::single_use_command_buffer_begin(void) +{ + VkCommandBuffer cmd_buf; + { + VkCommandBufferAllocateInfo info = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO}; + info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + info.commandPool = graphic_cmd_pool_; + info.commandBufferCount = 1; + vkAllocateCommandBuffers(device_, &info, &cmd_buf); + } + { + VkCommandBufferBeginInfo info = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; + info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkBeginCommandBuffer(cmd_buf, &info); + } + return cmd_buf; +} + +void VKContext::single_use_command_buffer_end(VkCommandBuffer cmd_buf) +{ + vkEndCommandBuffer(cmd_buf); + + this->submit_and_wait(cmd_buf); + + vkFreeCommandBuffers(device_, graphic_cmd_pool_, 1, &cmd_buf); +} + +void VKContext::submit_and_wait(VkCommandBuffer cmd_buf) +{ + { + VkSubmitInfo info = {VK_STRUCTURE_TYPE_SUBMIT_INFO}; + info.commandBufferCount = 1; + info.pCommandBuffers = &cmd_buf; + vkQueueSubmit(graphic_queue_, 1, &info, VK_NULL_HANDLE); + } + vkQueueWaitIdle(graphic_queue_); +} + +/** \} */ + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_context.hh b/source/blender/gpu/vulkan/vk_context.hh new file mode 100644 index 00000000000..0a78ef356c6 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_context.hh @@ -0,0 +1,100 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2020, Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_context_private.hh" + +#include "vk_mem_alloc.h" + +#include <vulkan/vulkan.h> + +#include "vk_state.hh" + +namespace blender { +namespace gpu { + +class VKContext : public Context { + public: + /** Capabilities. */ + /** Extensions. */ + /** Workarounds. */ + + private: + /** Copies of the handles owned by the GHOST context. */ + VkInstance instance_ = VK_NULL_HANDLE; + VkPhysicalDevice physical_device_ = VK_NULL_HANDLE; + VkDevice device_ = VK_NULL_HANDLE; + VkQueue graphic_queue_ = VK_NULL_HANDLE; + uint32_t graphic_queue_familly_ = 0; + + /** Command pool for graphics. */ + VkCommandPool graphic_cmd_pool_ = VK_NULL_HANDLE; + /** Allocator used for texture and buffers. */ + VmaAllocator mem_allocator_ = VK_NULL_HANDLE; + /** Last used framebuffer ghost UUID. + * This is used to detect when to recreate the #VKFrameBuffer. */ + uint32_t fb_id_ = -1; + + public: + VKContext(void *ghost_window, void *ghost_context); + ~VKContext(); + + void activate(void) override; + void deactivate(void) override; + + void flush(void) override{}; + void finish(void) override{}; + + void memory_statistics_get(int *total_mem, int *free_mem) override{}; + + static VKContext *get(void) + { + return static_cast<VKContext *>(Context::get()); + } + + VkDevice device_get(void) const + { + return device_; + } + + VkPhysicalDevice physical_device_get() const + { + return physical_device_; + } + + VmaAllocator mem_allocator_get(void) const + { + return mem_allocator_; + } + + /* Command buffers */ + VkCommandBuffer single_use_command_buffer_begin(void); + void single_use_command_buffer_end(VkCommandBuffer cmd_buf); + void submit_and_wait(VkCommandBuffer cmd_buf); + + MEM_CXX_CLASS_ALLOC_FUNCS("VKContext") +}; + +} // namespace gpu +} // namespace blender diff --git a/source/blender/gpu/vulkan/vk_drawlist.hh b/source/blender/gpu/vulkan/vk_drawlist.hh new file mode 100644 index 00000000000..3989a1f8ab9 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_drawlist.hh @@ -0,0 +1,57 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * Implementation of Multi Draw Indirect using OpenGL. + * Fallback if the needed extensions are not supported. + */ + +#pragma once + +#include "MEM_guardedalloc.h" + +#include "BLI_sys_types.h" + +#include "GPU_batch.h" + +#include "gpu_drawlist_private.hh" + +#include "vk_context.hh" + +namespace blender { +namespace gpu { + +/** + * Implementation of Multi Draw Indirect using OpenGL. + **/ +class VKDrawList : public DrawList { + public: + VKDrawList(int length){}; + ~VKDrawList(){}; + + void append(GPUBatch *batch, int i_first, int i_count) override{}; + void submit(void) override{}; + + MEM_CXX_CLASS_ALLOC_FUNCS("VKDrawList"); +}; + +} // namespace gpu +} // namespace blender diff --git a/source/blender/gpu/vulkan/vk_framebuffer.cc b/source/blender/gpu/vulkan/vk_framebuffer.cc new file mode 100644 index 00000000000..5335af373be --- /dev/null +++ b/source/blender/gpu/vulkan/vk_framebuffer.cc @@ -0,0 +1,78 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#include "BLI_vector.hh" + +#include "vk_context.hh" +#include "vk_texture.hh" + +#include "vk_framebuffer.hh" + +namespace blender::gpu { + +/* -------------------------------------------------------------------- */ +/** \name Creation & Deletion + * \{ */ + +VKFrameBuffer::VKFrameBuffer(const char *name) : FrameBuffer(name) +{ + /* Just-In-Time init. See #VKFrameBuffer::init(). */ + immutable_ = false; +} + +VKFrameBuffer::VKFrameBuffer(const char *name, + VkFramebuffer framebuffer, + VkCommandBuffer command_buffer, + VkRenderPass render_pass, + VkExtent2D extent) + : FrameBuffer(name) +{ + immutable_ = true; + /* Never update an internal frame-buffer. */ + dirty_attachments_ = false; + width_ = extent.width; + height_ = extent.height; + vk_fb_ = framebuffer; + + viewport_[0] = scissor_[0] = 0; + viewport_[1] = scissor_[1] = 0; + viewport_[2] = scissor_[2] = width_; + viewport_[3] = scissor_[3] = height_; +} + +VKFrameBuffer::~VKFrameBuffer() +{ + if (!immutable_ && vk_fb_ != VK_NULL_HANDLE) { + vkDestroyFramebuffer(vk_device_, vk_fb_, NULL); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Config + * \{ */ + +/** \} */ + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_framebuffer.hh b/source/blender/gpu/vulkan/vk_framebuffer.hh new file mode 100644 index 00000000000..abe92abfe8c --- /dev/null +++ b/source/blender/gpu/vulkan/vk_framebuffer.hh @@ -0,0 +1,114 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * Encapsulation of Framebuffer states (attached textures, viewport, scissors). + */ + +#pragma once + +#include "MEM_guardedalloc.h" + +#include <vulkan/vulkan.h> + +#include "gpu_framebuffer_private.hh" + +namespace blender::gpu { + +class VKContext; + +#define VK_MAX_ATTACHMENT (GPU_FB_MAX_COLOR_ATTACHMENT + 1) + +/** + * Implementation of FrameBuffer object using Vulkan. + **/ +class VKFrameBuffer : public FrameBuffer { + private: + /* Vulkan object handle. */ + VkFramebuffer vk_fb_ = VK_NULL_HANDLE; + /* Vulkan device who created the handle. */ + VkDevice vk_device_ = VK_NULL_HANDLE; + /* Base render pass used for framebuffer creation. */ + VkRenderPass render_pass_ = VK_NULL_HANDLE; + /* Number of layers if the attachments are layered textures. */ + int depth_ = 1; + /** Internal frame-buffers are immutable. */ + bool immutable_; + + public: + /** + * Create a conventional framebuffer to attach texture to. + **/ + VKFrameBuffer(const char *name); + + /** + * Special frame-buffer encapsulating internal window frame-buffer. + * This just act as a wrapper, the actual allocations are done by GHOST_ContextVK. + **/ + VKFrameBuffer(const char *name, + VkFramebuffer framebuffer, + VkCommandBuffer command_buffer, + VkRenderPass render_pass, + VkExtent2D extent); + + ~VKFrameBuffer(); + + void bind(bool enabled_srgb) override{}; + + bool check(char err_out[256]) override + { + return true; + }; + + void clear(eGPUFrameBufferBits buffers, + const float clear_col[4], + float clear_depth, + uint clear_stencil) override{}; + void clear_multi(const float (*clear_cols)[4]) override{}; + void clear_attachment(GPUAttachmentType type, + eGPUDataFormat data_format, + const void *clear_value) override{}; + + void read(eGPUFrameBufferBits planes, + eGPUDataFormat format, + const int area[4], + int channel_len, + int slot, + void *r_data) override{}; + + void blit_to(eGPUFrameBufferBits planes, + int src_slot, + FrameBuffer *dst, + int dst_slot, + int dst_offset_x, + int dst_offset_y) override{}; + + private: + MEM_CXX_CLASS_ALLOC_FUNCS("VKFrameBuffer"); +}; + +/* -------------------------------------------------------------------- */ +/** \name Enums Conversion + * \{ */ + +/** \} */ + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_immediate.hh b/source/blender/gpu/vulkan/vk_immediate.hh new file mode 100644 index 00000000000..587c77b4aaa --- /dev/null +++ b/source/blender/gpu/vulkan/vk_immediate.hh @@ -0,0 +1,49 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016 by Mike Erwin. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * Mimics old style opengl immediate mode drawing. + */ + +#pragma once + +#include "MEM_guardedalloc.h" + +#include "gpu_immediate_private.hh" + +namespace blender::gpu { + +class VKImmediate : public Immediate { + private: + uchar data_[4 * 1024 * 1024]; + + public: + VKImmediate(){}; + ~VKImmediate(){}; + + uchar *begin(void) override + { + return data_; + }; + void end(void) override{}; +}; + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_index_buffer.hh b/source/blender/gpu/vulkan/vk_index_buffer.hh new file mode 100644 index 00000000000..8e1428c66f3 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_index_buffer.hh @@ -0,0 +1,46 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "MEM_guardedalloc.h" + +#include "gpu_index_buffer_private.hh" + +namespace blender::gpu { + +class VKIndexBuf : public IndexBuf { + public: + ~VKIndexBuf(){}; + + void bind_as_ssbo(uint binding) override{}; + + const uint32_t *read() const override + { + return nullptr; + }; + + MEM_CXX_CLASS_ALLOC_FUNCS("VKIndexBuf") +}; + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_primitive.hh b/source/blender/gpu/vulkan/vk_primitive.hh new file mode 100644 index 00000000000..fbc28388b3a --- /dev/null +++ b/source/blender/gpu/vulkan/vk_primitive.hh @@ -0,0 +1,53 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * Encapsulation of Framebuffer states (attached textures, viewport, scissors). + */ + +#pragma once + +#include "BLI_assert.h" + +#include "GPU_primitive.h" + +namespace blender::gpu { + +static inline GLenum to_gl(GPUPrimType prim_type) +{ + BLI_assert(prim_type != GPU_PRIM_NONE); + switch (prim_type) { + default: + case GPU_PRIM_POINTS: + case GPU_PRIM_LINES: + case GPU_PRIM_LINE_STRIP: + case GPU_PRIM_LINE_LOOP: + case GPU_PRIM_TRIS: + case GPU_PRIM_TRI_STRIP: + case GPU_PRIM_TRI_FAN: + case GPU_PRIM_LINES_ADJ: + case GPU_PRIM_LINE_STRIP_ADJ: + case GPU_PRIM_TRIS_ADJ: + return 0; + }; +} + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_query.hh b/source/blender/gpu/vulkan/vk_query.hh new file mode 100644 index 00000000000..f6579339329 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_query.hh @@ -0,0 +1,42 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2020, Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_query.hh" + +namespace blender::gpu { + +class VKQueryPool : public QueryPool { + public: + ~VKQueryPool(){}; + + void init(GPUQueryType type) override{}; + + void begin_query(void) override{}; + void end_query(void) override{}; + + void get_occlusion_result(MutableSpan<uint32_t> r_values) override{}; +}; + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc new file mode 100644 index 00000000000..4f2af6093af --- /dev/null +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -0,0 +1,281 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#include "vk_shader.hh" + +#include <string> + +#include "BLI_vector.hh" + +#include "shader_compiler.hh" + +namespace blender::gpu { + +/* -------------------------------------------------------------------- */ +/** \name Shader stages + * \{ */ + +constexpr StringRef SHADER_STAGE_VERTEX_SHADER = "vertex"; +constexpr StringRef SHADER_STAGE_GEOMETRY_SHADER = "geometry"; +constexpr StringRef SHADER_STAGE_FRAGMENT_SHADER = "fragment"; +constexpr StringRef SHADER_STAGE_COMPUTE_SHADER = "compute"; + +std::ostream &operator<<(std::ostream &os, const VKShaderStageType &stage) +{ + switch (stage) { + case VKShaderStageType::VertexShader: + os << SHADER_STAGE_VERTEX_SHADER; + break; + case VKShaderStageType::GeometryShader: + os << SHADER_STAGE_GEOMETRY_SHADER; + break; + case VKShaderStageType::FragmentShader: + os << SHADER_STAGE_FRAGMENT_SHADER; + break; + case VKShaderStageType::ComputeShader: + os << SHADER_STAGE_COMPUTE_SHADER; + break; + } + return os; +} + +static shader_compiler::SourceType to_source_type(VKShaderStageType stage) +{ + switch (stage) { + case VKShaderStageType::VertexShader: + return shader_compiler::SourceType::GlslVertexShader; + break; + case VKShaderStageType::GeometryShader: + return shader_compiler::SourceType::GlslGeometryShader; + break; + case VKShaderStageType::FragmentShader: + return shader_compiler::SourceType::GlslFragmentShader; + break; + case VKShaderStageType::ComputeShader: + return shader_compiler::SourceType::GlslComputeShader; + break; + } + BLI_assert(!"Unknown VKShaderStageType."); + return shader_compiler::SourceType::GlslVertexShader; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Construction/Destruction + * \{ */ + +VKShader::VKShader(const char *name) : Shader(name) +{ + interface = new VKShaderInterface(); + context_ = VKContext::get(); +}; + +VKShader::~VKShader() +{ + VkDevice device = context_->device_get(); + if (vertex_shader_ != VK_NULL_HANDLE) { + vkDestroyShaderModule(device, vertex_shader_, nullptr); + vertex_shader_ = VK_NULL_HANDLE; + } + if (geometry_shader_ != VK_NULL_HANDLE) { + vkDestroyShaderModule(device, geometry_shader_, nullptr); + geometry_shader_ = VK_NULL_HANDLE; + } + if (fragment_shader_ != VK_NULL_HANDLE) { + vkDestroyShaderModule(device, fragment_shader_, nullptr); + fragment_shader_ = VK_NULL_HANDLE; + } + if (compute_shader_ != VK_NULL_HANDLE) { + vkDestroyShaderModule(device, compute_shader_, nullptr); + compute_shader_ = VK_NULL_HANDLE; + } + + context_ = nullptr; +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Compilation + * \{ */ + +static std::string to_stage_name(VKShaderStageType stage) +{ + std::stringstream ss; + ss << stage; + return ss.str(); +} + +static std::string to_stage_name(StringRef name, VKShaderStageType stage) +{ + std::stringstream ss; + ss << name << "." << stage; + return ss.str(); +} + +static std::string combine_sources(Span<const char *> sources) +{ + std::stringstream combined; + for (int i = 0; i < sources.size(); i++) { + combined << sources[i]; + } + return combined.str(); +} +static char *glsl_patch_get() +{ + static char patch[512] = "\0"; + if (patch[0] != '\0') { + return patch; + } + + size_t slen = 0; + /* Version need to go first. */ + STR_CONCAT(patch, slen, "#version 330\n"); + + BLI_assert(slen < sizeof(patch)); + return patch; +} + +std::unique_ptr<std::vector<uint32_t>> VKShader::compile_source(Span<const char *> sources, + VKShaderStageType stage) +{ + std::string stage_name = to_stage_name(name, stage); + + std::string source = combine_sources(sources); + + shader_compiler::Compiler *compiler = shader_compiler::Compiler::create_default(); + shader_compiler::Job job; + job.name = stage_name; + job.source = source; + job.compilation_target = shader_compiler::TargetType::SpirV; + job.source_type = to_source_type(stage); + + shader_compiler::Result *result = compiler->compile(job); + + if (!result) { + return std::make_unique<std::vector<uint32_t>>(); + } + + /* Log compilation errors/warnings. */ + if (!result->error_log.empty()) { + const char *error_log = result->error_log.c_str(); + std::vector<char> error(error_log, error_log + result->error_log.size() + 1); + VKLogParser parser; + print_log(sources, + error.data(), + to_stage_name(stage).c_str(), + result->status_code == shader_compiler::StatusCode::CompilationError, + &parser); + BLI_assert(!"Failed to compile shader!"); + } + + /* Retrieve compiled code. */ + std::unique_ptr<std::vector<uint32_t>> bin = std::make_unique<std::vector<uint32_t>>(); + switch (result->status_code) { + case shader_compiler::StatusCode::Ok: + bin = std::make_unique<std::vector<uint32_t>>(std::move(result->bin)); + break; + case shader_compiler::StatusCode::CompilationError: + break; + } + + delete result; + delete compiler; + return bin; +} + +VkShaderModule VKShader::create_shader_module(MutableSpan<const char *> sources, + VKShaderStageType stage) +{ + /* Patch the shader code using the first source slot. */ + sources[0] = glsl_patch_get(); + + std::unique_ptr<std::vector<uint32_t>> code = compile_source(sources, stage); + if (!code || code->size() == 0) { + compilation_failed_ = true; + return VK_NULL_HANDLE; + } + + VkDevice device = context_->device_get(); + VkShaderModuleCreateInfo shader_info = {}; + shader_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + shader_info.codeSize = code->size(); + shader_info.pCode = reinterpret_cast<const uint32_t *>(code->data()); + + VkShaderModule shader_module; + if (vkCreateShaderModule(device, &shader_info, nullptr, &shader_module) != VK_SUCCESS) { + return VK_NULL_HANDLE; + } + + return shader_module; +} + +void VKShader::vertex_shader_from_glsl(MutableSpan<const char *> sources) +{ +#ifdef WITH_VULKAN_SHADER_COMPILATION + vertex_shader_ = this->create_shader_module(sources, VKShaderStageType::VertexShader); +#endif +} + +void VKShader::geometry_shader_from_glsl(MutableSpan<const char *> sources) +{ +#ifdef WITH_VULKAN_SHADER_COMPILATION + geometry_shader_ = this->create_shader_module(sources, VKShaderStageType::GeometryShader); +#endif +} + +void VKShader::fragment_shader_from_glsl(MutableSpan<const char *> sources) +{ +#ifdef WITH_VULKAN_SHADER_COMPILATION + fragment_shader_ = this->create_shader_module(sources, VKShaderStageType::FragmentShader); +#endif +} + +void VKShader::compute_shader_from_glsl(MutableSpan<const char *> sources) +{ +#ifdef WITH_VULKAN_SHADER_COMPILATION + compute_shader_ = this->create_shader_module(sources, VKShaderStageType::ComputeShader); +#endif +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Linking + * \{ */ + +bool VKShader::finalize(void) +{ +#ifdef WITH_VULKAN_SHADER_COMPILATION + if (compilation_failed_) { + return false; + } +#endif + + return true; +}; + +/** \} */ + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_shader.hh b/source/blender/gpu/vulkan/vk_shader.hh new file mode 100644 index 00000000000..6376b17079d --- /dev/null +++ b/source/blender/gpu/vulkan/vk_shader.hh @@ -0,0 +1,115 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "MEM_guardedalloc.h" + +#include <vulkan/vulkan.h> + +#include "gpu_shader_private.hh" + +/* TODO move this deps to the .cc file. */ +#include "vk_context.hh" +#include "vk_shader_interface.hh" + +namespace blender { +namespace gpu { + +enum class VKShaderStageType { + VertexShader, + GeometryShader, + FragmentShader, + ComputeShader, +}; + +std::ostream &operator<<(std::ostream &os, const VKShaderStageType &stage); + +/** + * Implementation of shader compilation and uniforms handling using OpenGL. + **/ +class VKShader : public Shader { + private: + VKContext *context_ = nullptr; + + VkShaderModule vertex_shader_ = VK_NULL_HANDLE; + VkShaderModule geometry_shader_ = VK_NULL_HANDLE; + VkShaderModule fragment_shader_ = VK_NULL_HANDLE; + VkShaderModule compute_shader_ = VK_NULL_HANDLE; + + /** True if any shader failed to compile. */ + bool compilation_failed_ = false; + + public: + VKShader(const char *name); + ~VKShader(); + + void vertex_shader_from_glsl(MutableSpan<const char *> sources) override; + void geometry_shader_from_glsl(MutableSpan<const char *> sources) override; + void fragment_shader_from_glsl(MutableSpan<const char *> sources) override; + void compute_shader_from_glsl(MutableSpan<const char *> sources) override; + /* Return true on success. */ + bool finalize(void); + + void transform_feedback_names_set(Span<const char *> name_list, + const eGPUShaderTFBType geom_type) override{}; + bool transform_feedback_enable(GPUVertBuf *buf) override + { + return true; + }; + void transform_feedback_disable(void) override{}; + + void bind(void) override{}; + void unbind(void) override{}; + + void uniform_float(int location, int comp_len, int array_size, const float *data) override{}; + void uniform_int(int location, int comp_len, int array_size, const int *data) override{}; + + void vertformat_from_shader(GPUVertFormat *format) const override{}; + + int program_handle_get() const override + { + return 0; + } + + private: + std::unique_ptr<std::vector<uint32_t>> compile_source(Span<const char *> sources, + VKShaderStageType stage); + VkShaderModule create_shader_module(MutableSpan<const char *> sources, VKShaderStageType stage); + + MEM_CXX_CLASS_ALLOC_FUNCS("VKShader"); +}; + +class VKLogParser : public GPULogParser { + public: + char *parse_line(char *log_line, GPULogItem &log_item) override; + + protected: + char *skip_name_and_stage(char *log_line); + char *skip_severity_keyword(char *log_line, GPULogItem &log_item); + + MEM_CXX_CLASS_ALLOC_FUNCS("GLLogParser"); +}; + +} // namespace gpu +} // namespace blender diff --git a/source/blender/gpu/vulkan/vk_shader_interface.hh b/source/blender/gpu/vulkan/vk_shader_interface.hh new file mode 100644 index 00000000000..b9047f44cf9 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_shader_interface.hh @@ -0,0 +1,60 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * GPU shader interface (C --> GLSL) + * + * Structure detailing needed vertex inputs and resources for a specific shader. + * A shader interface can be shared between two similar shaders. + */ + +#pragma once + +#include "MEM_guardedalloc.h" + +#include "gpu_shader_interface.hh" + +namespace blender::gpu { + +class GLVaoCache; + +/** + * Implementation of Shader interface using OpenGL. + **/ +class VKShaderInterface : public ShaderInterface { + public: + VKShaderInterface() + { + inputs_ = (ShaderInput *)MEM_callocN(sizeof(*inputs_), __func__); + name_buffer_ = (char *)MEM_callocN(1, __func__); + for (int i = 0; i < GPU_NUM_UNIFORMS; i++) { + builtins_[i] = 0; + } + for (int i = 0; i < GPU_NUM_UNIFORM_BLOCKS; i++) { + builtin_blocks_[i] = 0; + } + }; + ~VKShaderInterface(){}; + + MEM_CXX_CLASS_ALLOC_FUNCS("VKShaderInterface"); +}; + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_shader_log.cc b/source/blender/gpu/vulkan/vk_shader_log.cc new file mode 100644 index 00000000000..2958adef903 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_shader_log.cc @@ -0,0 +1,65 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#include "vk_shader.hh" + +#include "GPU_platform.h" + +namespace blender::gpu { + +char *VKLogParser::parse_line(char *log_line, GPULogItem &log_item) +{ + log_line = skip_name_and_stage(log_line); + log_line = skip_separators(log_line, ":"); + + /* Parse error line & char numbers. */ + if (at_number(log_line)) { + char *error_line_number_end; + log_item.cursor.row = parse_number(log_line, &error_line_number_end); + log_line = error_line_number_end; + } + log_line = skip_separators(log_line, ": "); + + /* Skip to message. Avoid redundant info. */ + log_line = skip_severity_keyword(log_line, log_item); + log_line = skip_separators(log_line, ": "); + + return log_line; +} + +char *VKLogParser::skip_name_and_stage(char *log_line) +{ + char *name_skip = skip_until(log_line, '.'); + if (name_skip == log_line) { + return log_line; + } + + return skip_until(name_skip, ':'); +} + +char *VKLogParser::skip_severity_keyword(char *log_line, GPULogItem &log_item) +{ + return skip_severity(log_line, log_item, "error", "warning"); +} + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_state.hh b/source/blender/gpu/vulkan/vk_state.hh new file mode 100644 index 00000000000..a6513f8ea1e --- /dev/null +++ b/source/blender/gpu/vulkan/vk_state.hh @@ -0,0 +1,61 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2020, Blender Foundation. + */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" + +#include "gpu_state_private.hh" + +namespace blender { +namespace gpu { + +/** + * State manager keeping track of the draw state and applying it before drawing. + * Opengl Implementation. + **/ +class VKStateManager : public StateManager { + public: + VKStateManager(){}; + + void apply_state(void) override{}; + void force_state(void) override{}; + + void issue_barrier(eGPUBarrier barrier_bits) override{}; + + void texture_bind(Texture *tex, eGPUSamplerState sampler, int unit) override{}; + void texture_unbind(Texture *tex) override{}; + void texture_unbind_all(void) override{}; + + void image_bind(Texture *tex, int unit) override{}; + void image_unbind(Texture *tex) override{}; + void image_unbind_all(void) override{}; + + void texture_unpack_row_length_set(uint len) override{}; + + MEM_CXX_CLASS_ALLOC_FUNCS("VKStateManager") +}; + +} // namespace gpu +} // namespace blender diff --git a/source/blender/gpu/vulkan/vk_texture.cc b/source/blender/gpu/vulkan/vk_texture.cc new file mode 100644 index 00000000000..d9cf15739c5 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_texture.cc @@ -0,0 +1,154 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#include "vk_context.hh" + +#include "vk_texture.hh" + +namespace blender::gpu { + +VKTexture::VKTexture(const char *name) : Texture(name) +{ + context_ = VKContext::get(); +} + +VKTexture::~VKTexture(void) +{ + VkDevice device = context_->device_get(); + for (VkImageView view : views_) { + if (view != VK_NULL_HANDLE) { + vkDestroyImageView(device, view, nullptr); + } + } + if (vk_image_ != VK_NULL_HANDLE) { + vkDestroyImage(device, vk_image_, nullptr); + } +} + +bool VKTexture::init_internal(void) +{ + VmaAllocator mem_allocator = context_->mem_allocator_get(); + { + /* Usage very rough for now to support same level of interaction as OpenGL in a simple way. + * TODO(fclem) improve this. */ + VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT; + usage |= (format_flag_ & GPU_FORMAT_DEPTH) ? VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT : + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + + VkImageCreateInfo info = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; + info.imageType = to_vk_image_type(type_); + info.extent.width = static_cast<uint32_t>(w_); + info.extent.height = static_cast<uint32_t>(h_); + info.extent.depth = static_cast<uint32_t>(d_); + /* TODO(fclem) mipmap support. */ + info.mipLevels = 1; + info.arrayLayers = this->layer_count(); + info.format = to_vk(format_); + info.samples = VK_SAMPLE_COUNT_1_BIT; + info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + /* TODO(fclem) improve this. */ + info.tiling = VK_IMAGE_TILING_LINEAR; + info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + info.usage = usage; + info.flags = 0; + + views_.resize(info.mipLevels * (info.arrayLayers + 1), VK_NULL_HANDLE); + + VmaAllocationCreateInfo alloc_info = {}; + alloc_info.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; + alloc_info.preferredFlags = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | + VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + alloc_info.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; + alloc_info.usage = VMA_MEMORY_USAGE_GPU_ONLY; + + vmaCreateImage(mem_allocator, &info, &alloc_info, &vk_image_, &vk_allocation_, nullptr); + } + + return true; +} + +void VKTexture::update_sub( + int mip, int offset[3], int extent[3], eGPUDataFormat type, const void *data) +{ +} + +void VKTexture::swizzle_set(const char swizzle_mask[4]) +{ + vk_swizzle_.r = swizzle_to_vk(swizzle_mask[0]); + vk_swizzle_.g = swizzle_to_vk(swizzle_mask[1]); + vk_swizzle_.b = swizzle_to_vk(swizzle_mask[2]); + vk_swizzle_.a = swizzle_to_vk(swizzle_mask[3]); + + /* The swizzling changed, we need to reconstruct all views. */ + VkDevice device = context_->device_get(); + for (VkImageView view : views_) { + if (view != VK_NULL_HANDLE) { + /* WARNING: This is potentially unsafe since the views might already be in used. + * In practice, swizzle_set is always used just after initialization or before usage. */ + vkDestroyImageView(device, view, nullptr); + view = VK_NULL_HANDLE; + } + } +} + +VkImageView VKTexture::create_image_view(int mip, int layer) +{ + VkDevice device = context_->device_get(); + + VkImageSubresourceRange range; + range.aspectMask = to_vk(format_flag_); + range.baseMipLevel = (mip > -1) ? mip : 0; + range.baseArrayLayer = (layer > -1) ? layer : 0; + range.levelCount = (mip > -1) ? 1 : VK_REMAINING_MIP_LEVELS; + range.layerCount = (layer > -1) ? 1 : VK_REMAINING_ARRAY_LAYERS; + + VkImageViewCreateInfo info = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + info.flags = 0; + info.image = vk_image_; + info.viewType = to_vk_image_view_type(type_); + info.format = vk_format_; + info.components = vk_swizzle_; + info.subresourceRange = range; + + VkImageView view; + vkCreateImageView(device, &info, nullptr, &view); + return view; +} + +VkImageView VKTexture::vk_image_view_get(int mip) +{ + return this->vk_image_view_get(mip, -1); +} + +VkImageView VKTexture::vk_image_view_get(int mip, int layer) +{ + int view_id = mip * (layer_count() + 1) + layer + 1; + VkImageView view = views_[view_id]; + if (view == VK_NULL_HANDLE) { + views_[view_id] = view = this->create_image_view(mip, layer); + } + return view; +} + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_texture.hh b/source/blender/gpu/vulkan/vk_texture.hh new file mode 100644 index 00000000000..a79d6242dd8 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_texture.hh @@ -0,0 +1,290 @@ + +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * GPU Framebuffer + * - this is a wrapper for an OpenGL framebuffer object (FBO). in practice + * multiple FBO's may be created. + * - actual FBO creation & config is deferred until GPU_framebuffer_bind or + * GPU_framebuffer_check_valid to allow creation & config while another + * opengl context is bound (since FBOs are not shared between ogl contexts). + */ + +#pragma once + +#include "MEM_guardedalloc.h" + +#include <vulkan/vulkan.h> + +#include "BLI_assert.h" +#include "BLI_vector.hh" + +#include "gpu_texture_private.hh" + +struct GPUFrameBuffer; + +namespace blender { +namespace gpu { + +class VKTexture : public Texture { + protected: + /* Vulkan context who created the object. */ + VKContext *context_ = nullptr; + /* Vulkan object handle. */ + VkImage vk_image_ = VK_NULL_HANDLE; + /* GPU Memory allocated by this object. */ + VmaAllocation vk_allocation_ = VK_NULL_HANDLE; + /* Vulkan format used to initialize the texture. */ + VkFormat vk_format_ = VK_FORMAT_MAX_ENUM; + /* Image views for each mipmap and each layer. */ + Vector<VkImageView> views_; + /* Swizzle state. */ + VkComponentMapping vk_swizzle_ = {VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY}; + + public: + VKTexture(const char *name); + ~VKTexture(); + + void update_sub( + int mip, int offset[3], int extent[3], eGPUDataFormat type, const void *data) override; + + void generate_mipmap(void) override{}; + void copy_to(Texture *dst) override{}; + void clear(eGPUDataFormat format, const void *data) override{}; + void swizzle_set(const char swizzle_mask[4]) override; + void mip_range_set(int min, int max) override{}; + void *read(int mip, eGPUDataFormat type) override + { + /* NOTE: mip_size_get() won't override any dimension that is equal to 0. */ + int extent[3] = {1, 1, 1}; + this->mip_size_get(mip, extent); + + size_t sample_len = extent[0] * extent[1] * extent[2]; + size_t sample_size = to_bytesize(format_, type); + size_t texture_size = sample_len * sample_size; + return MEM_callocN(texture_size, __func__); + }; + + /* TODO(fclem) Legacy. Should be removed at some point. */ + uint gl_bindcode_get(void) const override + { + return 0; + }; + + /* Vulkan specific functions. */ + VkImageView vk_image_view_get(int mip); + VkImageView vk_image_view_get(int mip, int layer); + + VkFormat vk_format_get(void) const + { + return this->vk_format_; + } + + protected: + bool init_internal(void) override; + bool init_internal(GPUVertBuf *vbo) override + { + return true; + }; + + VkImageView create_image_view(int mip, int layer); + + MEM_CXX_CLASS_ALLOC_FUNCS("VKTexture") +}; + +inline VkImageType to_vk_image_type(eGPUTextureType type) +{ + switch (type & (GPU_TEXTURE_1D | GPU_TEXTURE_2D | GPU_TEXTURE_3D)) { + case GPU_TEXTURE_1D: + return VK_IMAGE_TYPE_1D; + case GPU_TEXTURE_2D: + return VK_IMAGE_TYPE_2D; + case GPU_TEXTURE_3D: + return VK_IMAGE_TYPE_3D; + default: + BLI_assert(!"Wrong enum!"); + return VK_IMAGE_TYPE_MAX_ENUM; + } +} + +inline VkImageViewType to_vk_image_view_type(eGPUTextureType type) +{ + switch (type) { + case GPU_TEXTURE_1D: + return VK_IMAGE_VIEW_TYPE_1D; + case GPU_TEXTURE_2D: + return VK_IMAGE_VIEW_TYPE_2D; + case GPU_TEXTURE_3D: + return VK_IMAGE_VIEW_TYPE_3D; + case GPU_TEXTURE_CUBE: + return VK_IMAGE_VIEW_TYPE_CUBE; + case GPU_TEXTURE_1D_ARRAY: + return VK_IMAGE_VIEW_TYPE_1D_ARRAY; + case GPU_TEXTURE_2D_ARRAY: + return VK_IMAGE_VIEW_TYPE_2D_ARRAY; + case GPU_TEXTURE_CUBE_ARRAY: + return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; + default: + BLI_assert(!"Wrong enum!"); + return VK_IMAGE_VIEW_TYPE_MAX_ENUM; + } +} + +inline VkImageAspectFlags to_vk(eGPUTextureFormatFlag flag) +{ + if (flag & GPU_FORMAT_DEPTH) { + return VK_IMAGE_ASPECT_DEPTH_BIT; + } + return VK_IMAGE_ASPECT_COLOR_BIT; +} + +inline VkComponentSwizzle swizzle_to_vk(const char swizzle) +{ + switch (swizzle) { + default: + case 'x': + case 'r': + return VK_COMPONENT_SWIZZLE_R; + case 'y': + case 'g': + return VK_COMPONENT_SWIZZLE_G; + case 'z': + case 'b': + return VK_COMPONENT_SWIZZLE_B; + case 'w': + case 'a': + return VK_COMPONENT_SWIZZLE_A; + case '0': + return VK_COMPONENT_SWIZZLE_ZERO; + case '1': + return VK_COMPONENT_SWIZZLE_ONE; + } +} + +inline VkFormat to_vk(eGPUTextureFormat format) +{ + switch (format) { + /* Formats texture & renderbuffer */ + case GPU_RGBA8UI: + return VK_FORMAT_R8G8B8A8_UINT; + case GPU_RGBA8I: + return VK_FORMAT_R8G8B8A8_SINT; + case GPU_RGBA8: + return VK_FORMAT_R8G8B8A8_UNORM; + case GPU_RGBA32UI: + return VK_FORMAT_R32G32B32A32_UINT; + case GPU_RGBA32I: + return VK_FORMAT_R32G32B32A32_SINT; + case GPU_RGBA32F: + return VK_FORMAT_R32G32B32A32_SFLOAT; + case GPU_RGBA16UI: + return VK_FORMAT_R16G16B16A16_UINT; + case GPU_RGBA16I: + return VK_FORMAT_R16G16B16A16_SINT; + case GPU_RGBA16F: + return VK_FORMAT_R16G16B16A16_SFLOAT; + case GPU_RGBA16: + return VK_FORMAT_R16G16B16A16_UNORM; + case GPU_RG8UI: + return VK_FORMAT_R8G8_UINT; + case GPU_RG8I: + return VK_FORMAT_R8G8_SINT; + case GPU_RG8: + return VK_FORMAT_R8G8_UNORM; + case GPU_RG32UI: + return VK_FORMAT_R32G32_UINT; + case GPU_RG32I: + return VK_FORMAT_R32G32_SINT; + case GPU_RG32F: + return VK_FORMAT_R32G32_SFLOAT; + case GPU_RG16UI: + return VK_FORMAT_R16G16_UINT; + case GPU_RG16I: + return VK_FORMAT_R16G16_SINT; + case GPU_RG16F: + return VK_FORMAT_R16G16_SFLOAT; + case GPU_RG16: + return VK_FORMAT_R16G16_UNORM; + case GPU_R8UI: + return VK_FORMAT_R8_UINT; + case GPU_R8I: + return VK_FORMAT_R8_SINT; + case GPU_R8: + return VK_FORMAT_R8_UNORM; + case GPU_R32UI: + return VK_FORMAT_R32_UINT; + case GPU_R32I: + return VK_FORMAT_R32_SINT; + case GPU_R32F: + return VK_FORMAT_R32_SFLOAT; + case GPU_R16UI: + return VK_FORMAT_R16_UINT; + case GPU_R16I: + return VK_FORMAT_R16_SINT; + case GPU_R16F: + return VK_FORMAT_R16_SFLOAT; + case GPU_R16: + return VK_FORMAT_R16_UNORM; + /* Special formats texture & renderbuffer */ + case GPU_RGB10_A2: + return VK_FORMAT_A2R10G10B10_UNORM_PACK32; + case GPU_R11F_G11F_B10F: + return VK_FORMAT_B10G11R11_UFLOAT_PACK32; + case GPU_DEPTH32F_STENCIL8: + return VK_FORMAT_D32_SFLOAT_S8_UINT; + case GPU_DEPTH24_STENCIL8: + return VK_FORMAT_D24_UNORM_S8_UINT; + case GPU_SRGB8_A8: + return VK_FORMAT_A8B8G8R8_SRGB_PACK32; + /* Texture only format */ + case GPU_RGB16F: + return VK_FORMAT_R16G16B16_SFLOAT; + /* Special formats texture only */ + case GPU_SRGB8_A8_DXT1: + return VK_FORMAT_BC1_RGBA_SRGB_BLOCK; + case GPU_SRGB8_A8_DXT3: + return VK_FORMAT_BC2_SRGB_BLOCK; + case GPU_SRGB8_A8_DXT5: + return VK_FORMAT_BC3_SRGB_BLOCK; + case GPU_RGBA8_DXT1: + return VK_FORMAT_BC1_RGBA_UNORM_BLOCK; + case GPU_RGBA8_DXT3: + return VK_FORMAT_BC2_UNORM_BLOCK; + case GPU_RGBA8_DXT5: + return VK_FORMAT_BC3_UNORM_BLOCK; + /* Depth Formats */ + case GPU_DEPTH_COMPONENT32F: + return VK_FORMAT_D32_SFLOAT; + case GPU_DEPTH_COMPONENT24: + return VK_FORMAT_X8_D24_UNORM_PACK32; + case GPU_DEPTH_COMPONENT16: + return VK_FORMAT_D16_UNORM; + } + BLI_assert(!"Unable to convert to vulkan textureformat."); + return VK_FORMAT_R32G32B32A32_SFLOAT; +} + +} // namespace gpu +} // namespace blender diff --git a/source/blender/gpu/vulkan/vk_uniform_buffer.hh b/source/blender/gpu/vulkan/vk_uniform_buffer.hh new file mode 100644 index 00000000000..36e231c5bf7 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_uniform_buffer.hh @@ -0,0 +1,52 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "MEM_guardedalloc.h" + +#include "gpu_uniform_buffer_private.hh" + +namespace blender { +namespace gpu { + +/** + * Implementation of Uniform Buffers using OpenGL. + **/ +class VKUniformBuf : public UniformBuf { + public: + VKUniformBuf(size_t size, const char *name) : UniformBuf(size, name){}; + ~VKUniformBuf(){}; + + void update(const void *data) override{}; + void bind(int slot) override{}; + void unbind(void) override{}; + + private: + void init(void); + + MEM_CXX_CLASS_ALLOC_FUNCS("VKUniformBuf"); +}; + +} // namespace gpu +} // namespace blender diff --git a/source/blender/gpu/vulkan/vk_vertex_buffer.hh b/source/blender/gpu/vulkan/vk_vertex_buffer.hh new file mode 100644 index 00000000000..43d8ecbabaf --- /dev/null +++ b/source/blender/gpu/vulkan/vk_vertex_buffer.hh @@ -0,0 +1,77 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "MEM_guardedalloc.h" + +#include "gpu_vertex_buffer_private.hh" + +namespace blender { +namespace gpu { + +class VKVertBuf : public VertBuf { + friend class VKTexture; /* For buffer texture. */ + + public: + void bind_as_ssbo(uint binding) override{}; + + void update_sub(uint start, uint len, void *data) override{}; + const void *read() const override + { + return nullptr; + }; + void *unmap(const void *mapped_data) const override{return nullptr;}; + + protected: + void acquire_data(void) override + { + MEM_SAFE_FREE(data); + data = (uchar *)MEM_mallocN(sizeof(uchar) * this->size_alloc_get(), __func__); + }; + void resize_data(void) override + { + data = (uchar *)MEM_reallocN(data, sizeof(uchar) * this->size_alloc_get()); + }; + void release_data(void) override + { + MEM_SAFE_FREE(data); + }; + void upload_data(void) override + { + if (usage_ == GPU_USAGE_STATIC) { + MEM_SAFE_FREE(data); + } + }; + void duplicate_data(VertBuf *dst) override + { + if (data != nullptr) { + dst->data = (uchar *)MEM_dupallocN(data); + } + }; + + MEM_CXX_CLASS_ALLOC_FUNCS("VKVertBuf"); +}; + +} // namespace gpu +} // namespace blender diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c index e416727fa70..ef6625d2cc6 100644 --- a/source/blender/python/generic/bgl.c +++ b/source/blender/python/generic/bgl.c @@ -29,6 +29,8 @@ #include "BLI_utildefines.h" #include "MEM_guardedalloc.h" +#include "BKE_global.h" + #include "GPU_state.h" #include "../generic/py_capi_utils.h" @@ -1116,6 +1118,25 @@ static PyObject *Buffer_repr(Buffer *self) ret_ret_##ret; \ } +#ifdef WITH_VULKAN +# undef BGL_Wrap +# define BGL_Wrap(funcname, ret, arg_list) \ + static PyObject *Method_##funcname(PyObject *UNUSED(self), PyObject *args) \ + { \ + arg_def arg_list; \ + ret_def_##ret; \ + if (!PyArg_ParseTuple(args, arg_str arg_list, arg_ref arg_list)) { \ + return NULL; \ + } \ + if (G.debug & G_DEBUG_VK_CONTEXT) { \ + return NULL; \ + } \ + GPU_bgl_start(); \ + ret_set_##ret gl##funcname(arg_var arg_list); \ + ret_ret_##ret; \ + } +#endif + /* GL_VERSION_1_0 */ BGL_Wrap(BlendFunc, void, (GLenum, GLenum)); BGL_Wrap(Clear, void, (GLbitfield)); diff --git a/source/blender/render/intern/pipeline.c b/source/blender/render/intern/pipeline.c index 1bf0dfe079c..7d9b5b90d62 100644 --- a/source/blender/render/intern/pipeline.c +++ b/source/blender/render/intern/pipeline.c @@ -977,7 +977,7 @@ void *RE_gl_context_get(Render *re) void *RE_gpu_context_get(Render *re) { if (re->gpu_context == NULL) { - re->gpu_context = GPU_context_create(NULL); + re->gpu_context = GPU_context_create(NULL, re->gl_context); } return re->gpu_context; } diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c index 640fef82085..905f9ff1353 100644 --- a/source/blender/windowmanager/intern/wm_playanim.c +++ b/source/blender/windowmanager/intern/wm_playanim.c @@ -1564,7 +1564,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv) // GHOST_ActivateWindowDrawingContext(g_WS.ghost_window); /* initialize OpenGL immediate mode */ - g_WS.gpu_context = GPU_context_create(g_WS.ghost_window); + g_WS.gpu_context = GPU_context_create(g_WS.ghost_window, NULL); GPU_init(); /* initialize the font */ diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 320047652df..a13fedd2283 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -551,6 +551,13 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, glSettings.flags |= GHOST_glDebugContext; } + GHOST_TDrawingContextType contextType = GHOST_kDrawingContextTypeOpenGL; +#ifdef WITH_VULKAN + if (G.debug & G_DEBUG_VK_CONTEXT) { + contextType = GHOST_kDrawingContextTypeVulkan; + } +#endif + int scr_w, scr_h; wm_get_desktopsize(&scr_w, &scr_h); int posy = (scr_h - win->posy - win->sizey); @@ -568,11 +575,11 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, win->sizey, (GHOST_TWindowState)win->windowstate, is_dialog, - GHOST_kDrawingContextTypeOpenGL, + contextType, glSettings); if (ghostwin) { - win->gpuctx = GPU_context_create(ghostwin); + win->gpuctx = GPU_context_create(ghostwin, NULL); /* needed so we can detect the graphics card below */ GPU_init(); @@ -2445,12 +2452,19 @@ void *WM_opengl_context_create(void) BLI_assert(BLI_thread_is_main()); BLI_assert(GPU_framebuffer_active_get() == GPU_framebuffer_back_get()); + GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeOpenGL; + +#ifdef WITH_VULKAN + if (G.debug & G_DEBUG_VK_CONTEXT) { + type = GHOST_kDrawingContextTypeVulkan; + } +#endif GHOST_GLSettings glSettings = {0}; if (G.debug & G_DEBUG_GPU) { glSettings.flags |= GHOST_glDebugContext; } - return GHOST_CreateOpenGLContext(g_system, GHOST_kDrawingContextTypeOpenGL, glSettings); + return GHOST_CreateOpenGLContext(g_system, type, glSettings); } void WM_opengl_context_dispose(void *context) |