diff options
Diffstat (limited to 'source/blender/gpu')
62 files changed, 1782 insertions, 429 deletions
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 7c6390971dd..f963d0e3b39 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -85,6 +85,7 @@ set(SRC GPU_buffers.h GPU_capabilities.h GPU_common.h + GPU_common_types.h GPU_compute.h GPU_context.h GPU_debug.h @@ -189,6 +190,7 @@ set(METAL_SRC metal/mtl_backend.mm metal/mtl_context.mm metal/mtl_debug.mm + metal/mtl_state.mm metal/mtl_texture.mm metal/mtl_texture_util.mm @@ -197,6 +199,7 @@ set(METAL_SRC metal/mtl_common.hh metal/mtl_context.hh metal/mtl_debug.hh + metal/mtl_state.hh metal/mtl_texture.hh ) @@ -301,7 +304,13 @@ set(GLSL_SRC shaders/gpu_shader_codegen_lib.glsl - shaders/gpu_shader_geometry.glsl + shaders/common/gpu_shader_common_color_ramp.glsl + shaders/common/gpu_shader_common_color_utils.glsl + shaders/common/gpu_shader_common_curves.glsl + shaders/common/gpu_shader_common_hash.glsl + shaders/common/gpu_shader_common_math.glsl + shaders/common/gpu_shader_common_math_utils.glsl + shaders/common/gpu_shader_common_mix_rgb.glsl shaders/material/gpu_shader_material_add_shader.glsl shaders/material/gpu_shader_material_ambient_occlusion.glsl @@ -315,8 +324,7 @@ set(GLSL_SRC shaders/material/gpu_shader_material_bump.glsl shaders/material/gpu_shader_material_camera.glsl shaders/material/gpu_shader_material_clamp.glsl - shaders/material/gpu_shader_material_color_ramp.glsl - shaders/material/gpu_shader_material_color_util.glsl + shaders/material/gpu_shader_material_combine_color.glsl shaders/material/gpu_shader_material_combine_hsv.glsl shaders/material/gpu_shader_material_combine_rgb.glsl shaders/material/gpu_shader_material_combine_xyz.glsl @@ -324,7 +332,6 @@ set(GLSL_SRC shaders/material/gpu_shader_material_displacement.glsl shaders/material/gpu_shader_material_eevee_specular.glsl shaders/material/gpu_shader_material_emission.glsl - shaders/material/gpu_shader_material_float_curve.glsl shaders/material/gpu_shader_material_fractal_noise.glsl shaders/material/gpu_shader_material_fresnel.glsl shaders/material/gpu_shader_material_gamma.glsl @@ -333,7 +340,6 @@ set(GLSL_SRC shaders/material/gpu_shader_material_glossy.glsl shaders/material/gpu_shader_material_hair_info.glsl shaders/material/gpu_shader_material_hair.glsl - shaders/material/gpu_shader_material_hash.glsl shaders/material/gpu_shader_material_holdout.glsl shaders/material/gpu_shader_material_hue_sat_val.glsl shaders/material/gpu_shader_material_invert.glsl @@ -342,9 +348,6 @@ set(GLSL_SRC shaders/material/gpu_shader_material_light_path.glsl shaders/material/gpu_shader_material_mapping.glsl shaders/material/gpu_shader_material_map_range.glsl - shaders/material/gpu_shader_material_math.glsl - shaders/material/gpu_shader_material_math_util.glsl - shaders/material/gpu_shader_material_mix_rgb.glsl shaders/material/gpu_shader_material_mix_shader.glsl shaders/material/gpu_shader_material_noise.glsl shaders/material/gpu_shader_material_normal.glsl @@ -357,8 +360,8 @@ set(GLSL_SRC shaders/material/gpu_shader_material_point_info.glsl shaders/material/gpu_shader_material_principled.glsl shaders/material/gpu_shader_material_refraction.glsl - shaders/material/gpu_shader_material_rgb_curves.glsl shaders/material/gpu_shader_material_rgb_to_bw.glsl + shaders/material/gpu_shader_material_separate_color.glsl shaders/material/gpu_shader_material_separate_hsv.glsl shaders/material/gpu_shader_material_separate_rgb.glsl shaders/material/gpu_shader_material_separate_xyz.glsl @@ -381,10 +384,10 @@ set(GLSL_SRC shaders/material/gpu_shader_material_tex_wave.glsl shaders/material/gpu_shader_material_tex_white_noise.glsl shaders/material/gpu_shader_material_toon.glsl + shaders/material/gpu_shader_material_transform_utils.glsl shaders/material/gpu_shader_material_translucent.glsl shaders/material/gpu_shader_material_transparent.glsl shaders/material/gpu_shader_material_uv_map.glsl - shaders/material/gpu_shader_material_vector_curves.glsl shaders/material/gpu_shader_material_vector_displacement.glsl shaders/material/gpu_shader_material_vector_math.glsl shaders/material/gpu_shader_material_vector_rotate.glsl @@ -496,6 +499,7 @@ set(SRC_SHADER_CREATE_INFOS shaders/infos/gpu_shader_2D_widget_info.hh shaders/infos/gpu_shader_3D_depth_only_info.hh shaders/infos/gpu_shader_3D_flat_color_info.hh + shaders/infos/gpu_shader_3D_image_info.hh shaders/infos/gpu_shader_3D_image_modulate_alpha_info.hh shaders/infos/gpu_shader_3D_point_info.hh shaders/infos/gpu_shader_3D_polyline_info.hh diff --git a/source/blender/gpu/GPU_common_types.h b/source/blender/gpu/GPU_common_types.h new file mode 100644 index 00000000000..e08143c2449 --- /dev/null +++ b/source/blender/gpu/GPU_common_types.h @@ -0,0 +1,18 @@ +/** \file + * \ingroup gpu + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum eGPUFrontFace { + GPU_CLOCKWISE, + GPU_COUNTERCLOCKWISE, +} eGPUFrontFace; + +#ifdef __cplusplus +} +#endif
\ No newline at end of file diff --git a/source/blender/gpu/GPU_legacy_stubs.h b/source/blender/gpu/GPU_legacy_stubs.h index 369347447f8..5970738a9b3 100644 --- a/source/blender/gpu/GPU_legacy_stubs.h +++ b/source/blender/gpu/GPU_legacy_stubs.h @@ -23,7 +23,7 @@ #include "BLI_utildefines.h" /** - * Empty function, use for breakpoint when a deprecated + * Empty function, use for break-point when a deprecated * OpenGL function is called. */ static void gl_deprecated(void) diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index b620fe9cc9d..3460d33fe68 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -280,6 +280,16 @@ typedef enum eGPUBuiltinShader { GPU_SHADER_2D_IMAGE_OVERLAYS_STEREO_MERGE, GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR, /** + * Draw a texture in 3D. Take a 3D position and a 2D texture coordinate for each vertex. + * + * Exposed via Python-API for add-ons. + * + * \param image: uniform sampler2D + * \param texCoord: in vec2 + * \param pos: in vec3 + */ + GPU_SHADER_3D_IMAGE, + /** * Draw texture with alpha. Take a 3D position and a 2D texture coordinate for each vertex. * * \param alpha: uniform float diff --git a/source/blender/gpu/GPU_state.h b/source/blender/gpu/GPU_state.h index 99b60351dcc..7519b3bc1cb 100644 --- a/source/blender/gpu/GPU_state.h +++ b/source/blender/gpu/GPU_state.h @@ -35,6 +35,19 @@ typedef enum eGPUBarrier { ENUM_OPERATORS(eGPUBarrier, GPU_BARRIER_ELEMENT_ARRAY) +/* NOTE: For Metal and Vulkan only. + * TODO(Metal): Update barrier calls to use stage flags. */ +typedef enum eGPUStageBarrierBits { + GPU_BARRIER_STAGE_VERTEX = (1 << 0), + GPU_BARRIER_STAGE_FRAGMENT = (1 << 1), + GPU_BARRIER_STAGE_COMPUTE = (1 << 2), + GPU_BARRIER_STAGE_ANY_GRAPHICS = (GPU_BARRIER_STAGE_VERTEX | GPU_BARRIER_STAGE_FRAGMENT), + GPU_BARRIER_STAGE_ANY = (GPU_BARRIER_STAGE_VERTEX | GPU_BARRIER_STAGE_FRAGMENT | + GPU_BARRIER_STAGE_COMPUTE), +} eGPUStageBarrierBits; + +ENUM_OPERATORS(eGPUStageBarrierBits, GPU_BARRIER_STAGE_COMPUTE) + /** * Defines the fixed pipeline blending equation. * SRC is the output color from the shader. diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index bb0912f284b..b045d908438 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -280,9 +280,9 @@ void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat data_format, int miplvl); /** * Fills the whole texture with the same data for all pixels. * \warning Only work for 2D texture for now. - * \warning Only clears the mip 0 of the texture. + * \warning Only clears the MIP 0 of the texture. * \param data_format: data format of the pixel data. - * \note The format is float for unorm textures. + * \note The format is float for UNORM textures. * \param data: 1 pixel worth of data to fill the texture with. */ void GPU_texture_clear(GPUTexture *tex, eGPUDataFormat data_format, const void *data); diff --git a/source/blender/gpu/GPU_vertex_buffer.h b/source/blender/gpu/GPU_vertex_buffer.h index fe6ed7eaf87..722ef878271 100644 --- a/source/blender/gpu/GPU_vertex_buffer.h +++ b/source/blender/gpu/GPU_vertex_buffer.h @@ -165,6 +165,7 @@ void GPU_vertbuf_tag_dirty(GPUVertBuf *verts); */ void GPU_vertbuf_use(GPUVertBuf *); void GPU_vertbuf_bind_as_ssbo(struct GPUVertBuf *verts, int binding); +void GPU_vertbuf_bind_as_texture(struct GPUVertBuf *verts, int binding); void GPU_vertbuf_wrap_handle(GPUVertBuf *verts, uint64_t handle); diff --git a/source/blender/gpu/GPU_vertex_format.h b/source/blender/gpu/GPU_vertex_format.h index c6b0d5902fe..bf8dc409cb7 100644 --- a/source/blender/gpu/GPU_vertex_format.h +++ b/source/blender/gpu/GPU_vertex_format.h @@ -55,7 +55,7 @@ typedef struct GPUVertAttr { /* 1 to 4 or 8 or 12 or 16 */ uint comp_len : 5; /* size in bytes, 1 to 64 */ - uint sz : 7; + uint size : 7; /* from beginning of vertex, in bytes */ uint offset : 11; /* up to GPU_VERT_ATTR_MAX_NAMES */ diff --git a/source/blender/gpu/intern/gpu_debug.cc b/source/blender/gpu/intern/gpu_debug.cc index c62a6416f92..055207eace8 100644 --- a/source/blender/gpu/intern/gpu_debug.cc +++ b/source/blender/gpu/intern/gpu_debug.cc @@ -50,11 +50,11 @@ void GPU_debug_get_groups_names(int name_buf_len, char *r_name_buf) r_name_buf[0] = '\0'; return; } - size_t sz = 0; + size_t len = 0; for (StringRef &name : stack) { - sz += BLI_snprintf_rlen(r_name_buf + sz, name_buf_len - sz, "%s > ", name.data()); + len += BLI_snprintf_rlen(r_name_buf + len, name_buf_len - len, "%s > ", name.data()); } - r_name_buf[sz - 3] = '\0'; + r_name_buf[len - 3] = '\0'; } bool GPU_debug_group_match(const char *ref) diff --git a/source/blender/gpu/intern/gpu_immediate.cc b/source/blender/gpu/intern/gpu_immediate.cc index 7dc1c739750..69467e5b28a 100644 --- a/source/blender/gpu/intern/gpu_immediate.cc +++ b/source/blender/gpu/intern/gpu_immediate.cc @@ -490,7 +490,7 @@ static void immEndVertex() /* and move on to the next vertex */ #endif uchar *data = imm->vertex_data + a->offset; - memcpy(data, data - imm->vertex_format.stride, a->sz); + memcpy(data, data - imm->vertex_format.stride, a->size); /* TODO: consolidate copy of adjacent attributes */ } } diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 7ec6ee5183a..23028f58059 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -626,7 +626,7 @@ eGPUMaterialFlag GPU_material_flag(const GPUMaterial *mat) return mat->flag; } -/* Note: Consumes the flags. */ +/* NOTE: Consumes the flags. */ bool GPU_material_recalc_flag_get(GPUMaterial *mat) { bool updated = (mat->flag & GPU_MATFLAG_UPDATED) != 0; diff --git a/source/blender/gpu/intern/gpu_shader_builtin.c b/source/blender/gpu/intern/gpu_shader_builtin.c index 1100272b712..b92fae4a89b 100644 --- a/source/blender/gpu/intern/gpu_shader_builtin.c +++ b/source/blender/gpu/intern/gpu_shader_builtin.c @@ -150,6 +150,11 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = { .name = "GPU_SHADER_SIMPLE_LIGHTING", .create_info = "gpu_shader_simple_lighting", }, + [GPU_SHADER_3D_IMAGE] = + { + .name = "GPU_SHADER_3D_IMAGE", + .create_info = "gpu_shader_3D_image", + }, [GPU_SHADER_3D_IMAGE_MODULATE_ALPHA] = { .name = "GPU_SHADER_3D_IMAGE_MODULATE_ALPHA", diff --git a/source/blender/gpu/intern/gpu_shader_dependency.cc b/source/blender/gpu/intern/gpu_shader_dependency.cc index f69c56b5f3f..aa2033b9154 100644 --- a/source/blender/gpu/intern/gpu_shader_dependency.cc +++ b/source/blender/gpu/intern/gpu_shader_dependency.cc @@ -593,7 +593,9 @@ struct GPUSource { bool is_from_material_library() const { - return filename.startswith("gpu_shader_material_") && filename.endswith(".glsl"); + return (filename.startswith("gpu_shader_material_") || + filename.startswith("gpu_shader_common_")) && + filename.endswith(".glsl"); } }; diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.cc b/source/blender/gpu/intern/gpu_vertex_buffer.cc index 2974547c858..f47970d48d1 100644 --- a/source/blender/gpu/intern/gpu_vertex_buffer.cc +++ b/source/blender/gpu/intern/gpu_vertex_buffer.cc @@ -199,7 +199,7 @@ void GPU_vertbuf_attr_set(GPUVertBuf *verts_, uint a_idx, uint v_idx, const void BLI_assert(a_idx < format->attr_len); BLI_assert(verts->data != nullptr); verts->flag |= GPU_VERTBUF_DATA_DIRTY; - memcpy(verts->data + a->offset + v_idx * format->stride, data, a->sz); + memcpy(verts->data + a->offset + v_idx * format->stride, data, a->size); } void GPU_vertbuf_attr_fill(GPUVertBuf *verts_, uint a_idx, const void *data) @@ -208,7 +208,7 @@ void GPU_vertbuf_attr_fill(GPUVertBuf *verts_, uint a_idx, const void *data) const GPUVertFormat *format = &verts->format; BLI_assert(a_idx < format->attr_len); const GPUVertAttr *a = &format->attrs[a_idx]; - const uint stride = a->sz; /* tightly packed input data */ + const uint stride = a->size; /* tightly packed input data */ verts->flag |= GPU_VERTBUF_DATA_DIRTY; GPU_vertbuf_attr_fill_stride(verts_, a_idx, stride, data); } @@ -235,13 +235,13 @@ void GPU_vertbuf_attr_fill_stride(GPUVertBuf *verts_, uint a_idx, uint stride, c if (format->attr_len == 1 && stride == format->stride) { /* we can copy it all at once */ - memcpy(verts->data, data, vertex_len * a->sz); + memcpy(verts->data, data, vertex_len * a->size); } else { /* we must copy it per vertex */ for (uint v = 0; v < vertex_len; v++) { memcpy( - verts->data + a->offset + v * format->stride, (const uchar *)data + v * stride, a->sz); + verts->data + a->offset + v * format->stride, (const uchar *)data + v * stride, a->size); } } } @@ -256,7 +256,7 @@ void GPU_vertbuf_attr_get_raw_data(GPUVertBuf *verts_, uint a_idx, GPUVertBufRaw verts->flag |= GPU_VERTBUF_DATA_DIRTY; verts->flag &= ~GPU_VERTBUF_DATA_UPLOADED; - access->size = a->sz; + access->size = a->size; access->stride = format->stride; access->data = (uchar *)verts->data + a->offset; access->data_init = access->data; @@ -328,6 +328,11 @@ void GPU_vertbuf_bind_as_ssbo(struct GPUVertBuf *verts, int binding) unwrap(verts)->bind_as_ssbo(binding); } +void GPU_vertbuf_bind_as_texture(struct GPUVertBuf *verts, int binding) +{ + unwrap(verts)->bind_as_texture(binding); +} + void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, const void *data) { unwrap(verts)->update_sub(start, len, data); diff --git a/source/blender/gpu/intern/gpu_vertex_buffer_private.hh b/source/blender/gpu/intern/gpu_vertex_buffer_private.hh index e5b70de9dfa..7a0b53cf958 100644 --- a/source/blender/gpu/intern/gpu_vertex_buffer_private.hh +++ b/source/blender/gpu/intern/gpu_vertex_buffer_private.hh @@ -51,6 +51,7 @@ class VertBuf { void resize(uint vert_len); void upload(); virtual void bind_as_ssbo(uint binding) = 0; + virtual void bind_as_texture(uint binding) = 0; virtual void wrap_handle(uint64_t handle) = 0; diff --git a/source/blender/gpu/intern/gpu_vertex_format.cc b/source/blender/gpu/intern/gpu_vertex_format.cc index a9ac191754b..59ae862aa51 100644 --- a/source/blender/gpu/intern/gpu_vertex_format.cc +++ b/source/blender/gpu/intern/gpu_vertex_format.cc @@ -49,7 +49,7 @@ void GPU_vertformat_copy(GPUVertFormat *dest, const GPUVertFormat *src) memcpy(dest, src, sizeof(GPUVertFormat)); } -static uint comp_sz(GPUVertCompType type) +static uint comp_size(GPUVertCompType type) { #if TRUST_NO_ONE assert(type <= GPU_COMP_F32); /* other types have irregular sizes (not bytes) */ @@ -58,12 +58,12 @@ static uint comp_sz(GPUVertCompType type) return sizes[type]; } -static uint attr_sz(const GPUVertAttr *a) +static uint attr_size(const GPUVertAttr *a) { if (a->comp_type == GPU_COMP_I10) { return 4; /* always packed as 10_10_10_2 */ } - return a->comp_len * comp_sz(static_cast<GPUVertCompType>(a->comp_type)); + return a->comp_len * comp_size(static_cast<GPUVertCompType>(a->comp_type)); } static uint attr_align(const GPUVertAttr *a) @@ -71,7 +71,7 @@ static uint attr_align(const GPUVertAttr *a) if (a->comp_type == GPU_COMP_I10) { return 4; /* always packed as 10_10_10_2 */ } - uint c = comp_sz(static_cast<GPUVertCompType>(a->comp_type)); + uint c = comp_size(static_cast<GPUVertCompType>(a->comp_type)); if (a->comp_len == 3 && c <= 2) { return 4 * c; /* AMD HW can't fetch these well, so pad it out (other vendors too?) */ } @@ -156,7 +156,7 @@ uint GPU_vertformat_attr_add(GPUVertFormat *format, attr->comp_len = (comp_type == GPU_COMP_I10) ? 4 : comp_len; /* system needs 10_10_10_2 to be 4 or BGRA */ - attr->sz = attr_sz(attr); + attr->size = attr_size(attr); attr->offset = 0; /* offsets & stride are calculated later (during pack) */ attr->fetch_mode = fetch_mode; @@ -294,13 +294,13 @@ uint padding(uint offset, uint alignment) } #if PACK_DEBUG -static void show_pack(uint a_idx, uint sz, uint pad) +static void show_pack(uint a_idx, uint size, uint pad) { const char c = 'A' + a_idx; for (uint i = 0; i < pad; i++) { putchar('-'); } - for (uint i = 0; i < sz; i++) { + for (uint i = 0; i < size; i++) { putchar(c); } } @@ -310,10 +310,10 @@ void VertexFormat_pack(GPUVertFormat *format) { GPUVertAttr *a0 = &format->attrs[0]; a0->offset = 0; - uint offset = a0->sz; + uint offset = a0->size; #if PACK_DEBUG - show_pack(0, a0->sz, 0); + show_pack(0, a0->size, 0); #endif for (uint a_idx = 1; a_idx < format->attr_len; a_idx++) { @@ -321,10 +321,10 @@ void VertexFormat_pack(GPUVertFormat *format) uint mid_padding = padding(offset, attr_align(a)); offset += mid_padding; a->offset = offset; - offset += a->sz; + offset += a->size; #if PACK_DEBUG - show_pack(a_idx, a->sz, mid_padding); + show_pack(a_idx, a->size, mid_padding); #endif } diff --git a/source/blender/gpu/metal/mtl_context.hh b/source/blender/gpu/metal/mtl_context.hh index aa198482291..1849a04ea48 100644 --- a/source/blender/gpu/metal/mtl_context.hh +++ b/source/blender/gpu/metal/mtl_context.hh @@ -7,8 +7,10 @@ #include "gpu_context_private.hh" +#include "GPU_common_types.h" #include "GPU_context.h" +#include "mtl_capabilities.hh" #include "mtl_texture.hh" #include <Cocoa/Cocoa.h> @@ -21,6 +23,112 @@ namespace blender::gpu { +class MTLShader; +class MTLUniformBuf; +class MTLBuffer; + +/* Depth Stencil State */ +typedef struct MTLContextDepthStencilState { + + /* Depth State. */ + bool depth_write_enable; + bool depth_test_enabled; + float depth_range_near; + float depth_range_far; + MTLCompareFunction depth_function; + float depth_bias; + float depth_slope_scale; + bool depth_bias_enabled_for_points; + bool depth_bias_enabled_for_lines; + bool depth_bias_enabled_for_tris; + + /* Stencil State. */ + bool stencil_test_enabled; + unsigned int stencil_read_mask; + unsigned int stencil_write_mask; + unsigned int stencil_ref; + MTLCompareFunction stencil_func; + + MTLStencilOperation stencil_op_front_stencil_fail; + MTLStencilOperation stencil_op_front_depth_fail; + MTLStencilOperation stencil_op_front_depthstencil_pass; + + MTLStencilOperation stencil_op_back_stencil_fail; + MTLStencilOperation stencil_op_back_depth_fail; + MTLStencilOperation stencil_op_back_depthstencil_pass; + + /* Frame-buffer State -- We need to mark this, in case stencil state remains unchanged, + * but attachment state has changed. */ + bool has_depth_target; + bool has_stencil_target; + + /* TODO(Metal): Consider optimizing this function using memcmp. + * Un-used, but differing, stencil state leads to over-generation + * of state objects when doing trivial compare. */ + inline bool operator==(const MTLContextDepthStencilState &other) const + { + bool depth_state_equality = (has_depth_target == other.has_depth_target && + depth_write_enable == other.depth_write_enable && + depth_test_enabled == other.depth_test_enabled && + depth_function == other.depth_function); + + bool stencil_state_equality = true; + if (has_stencil_target) { + stencil_state_equality = + (has_stencil_target == other.has_stencil_target && + stencil_test_enabled == other.stencil_test_enabled && + stencil_op_front_stencil_fail == other.stencil_op_front_stencil_fail && + stencil_op_front_depth_fail == other.stencil_op_front_depth_fail && + stencil_op_front_depthstencil_pass == other.stencil_op_front_depthstencil_pass && + stencil_op_back_stencil_fail == other.stencil_op_back_stencil_fail && + stencil_op_back_depth_fail == other.stencil_op_back_depth_fail && + stencil_op_back_depthstencil_pass == other.stencil_op_back_depthstencil_pass && + stencil_func == other.stencil_func && stencil_read_mask == other.stencil_read_mask && + stencil_write_mask == other.stencil_write_mask); + } + + return depth_state_equality && stencil_state_equality; + } + + /* Depth stencil state will get hashed in order to prepare + * MTLDepthStencilState objects. The hash should comprise of + * all elements which fill the MTLDepthStencilDescriptor. + * These are bound when [rec setDepthStencilState:...] is called. + * Depth bias and stencil reference value are set dynamically on the RenderCommandEncoder: + * - setStencilReferenceValue: + * - setDepthBias:slopeScale:clamp: + */ + inline std::size_t hash() const + { + std::size_t boolean_bitmask = (this->depth_write_enable ? 1 : 0) | + ((this->depth_test_enabled ? 1 : 0) << 1) | + ((this->depth_bias_enabled_for_points ? 1 : 0) << 2) | + ((this->depth_bias_enabled_for_lines ? 1 : 0) << 3) | + ((this->depth_bias_enabled_for_tris ? 1 : 0) << 4) | + ((this->stencil_test_enabled ? 1 : 0) << 5) | + ((this->has_depth_target ? 1 : 0) << 6) | + ((this->has_stencil_target ? 1 : 0) << 7); + + std::size_t stencilop_bitmask = ((std::size_t)this->stencil_op_front_stencil_fail) | + ((std::size_t)this->stencil_op_front_depth_fail << 3) | + ((std::size_t)this->stencil_op_front_depthstencil_pass << 6) | + ((std::size_t)this->stencil_op_back_stencil_fail << 9) | + ((std::size_t)this->stencil_op_back_depth_fail << 12) | + ((std::size_t)this->stencil_op_back_depthstencil_pass << 15); + + std::size_t main_hash = (std::size_t)this->depth_function; + if (this->has_stencil_target) { + main_hash += (std::size_t)(this->stencil_read_mask & 0xFF) << 8; + main_hash += (std::size_t)(this->stencil_write_mask & 0xFF) << 16; + } + main_hash ^= (std::size_t)this->stencil_func << 16; + main_hash ^= stencilop_bitmask; + + std::size_t final_hash = (main_hash << 8) | boolean_bitmask; + return final_hash; + } +} MTLContextDepthStencilState; + typedef struct MTLContextTextureUtils { /* Depth Update Utilities */ @@ -108,11 +216,149 @@ typedef struct MTLContextTextureUtils { } MTLContextTextureUtils; +/* Structs containing information on current binding state for textures and samplers. */ +typedef struct MTLTextureBinding { + bool used; + + /* Same value as index in bindings array. */ + unsigned int texture_slot_index; + gpu::MTLTexture *texture_resource; + +} MTLTextureBinding; + +typedef struct MTLSamplerBinding { + bool used; + MTLSamplerState state; + + bool operator==(MTLSamplerBinding const &other) const + { + return (used == other.used && state == other.state); + } +} MTLSamplerBinding; + +/* Combined sampler state configuration for Argument Buffer caching. */ +struct MTLSamplerArray { + unsigned int num_samplers; + /* MTLSamplerState permutations between 0..256 - slightly more than a byte. */ + MTLSamplerState mtl_sampler_flags[MTL_MAX_TEXTURE_SLOTS]; + id<MTLSamplerState> mtl_sampler[MTL_MAX_TEXTURE_SLOTS]; + + inline bool operator==(const MTLSamplerArray &other) const + { + if (this->num_samplers != other.num_samplers) { + return false; + } + return (memcmp(this->mtl_sampler_flags, + other.mtl_sampler_flags, + sizeof(MTLSamplerState) * this->num_samplers) == 0); + } + + inline uint32_t hash() const + { + uint32_t hash = this->num_samplers; + for (int i = 0; i < this->num_samplers; i++) { + hash ^= (uint32_t)this->mtl_sampler_flags[i] << (i % 3); + } + return hash; + } +}; + +typedef enum MTLPipelineStateDirtyFlag { + MTL_PIPELINE_STATE_NULL_FLAG = 0, + /* Whether we need to call setViewport. */ + MTL_PIPELINE_STATE_VIEWPORT_FLAG = (1 << 0), + /* Whether we need to call setScissor.*/ + MTL_PIPELINE_STATE_SCISSOR_FLAG = (1 << 1), + /* Whether we need to update/rebind active depth stencil state. */ + MTL_PIPELINE_STATE_DEPTHSTENCIL_FLAG = (1 << 2), + /* Whether we need to update/rebind active PSO. */ + MTL_PIPELINE_STATE_PSO_FLAG = (1 << 3), + /* Whether we need to update the frontFacingWinding state. */ + MTL_PIPELINE_STATE_FRONT_FACING_FLAG = (1 << 4), + /* Whether we need to update the culling state. */ + MTL_PIPELINE_STATE_CULLMODE_FLAG = (1 << 5), + /* Full pipeline state needs applying. Occurs when beginning a new render pass. */ + MTL_PIPELINE_STATE_ALL_FLAG = + (MTL_PIPELINE_STATE_VIEWPORT_FLAG | MTL_PIPELINE_STATE_SCISSOR_FLAG | + MTL_PIPELINE_STATE_DEPTHSTENCIL_FLAG | MTL_PIPELINE_STATE_PSO_FLAG | + MTL_PIPELINE_STATE_FRONT_FACING_FLAG | MTL_PIPELINE_STATE_CULLMODE_FLAG) +} MTLPipelineStateDirtyFlag; + +/* Ignore full flag bit-mask `MTL_PIPELINE_STATE_ALL_FLAG`. */ +ENUM_OPERATORS(MTLPipelineStateDirtyFlag, MTL_PIPELINE_STATE_CULLMODE_FLAG); + +typedef struct MTLUniformBufferBinding { + bool bound; + MTLUniformBuf *ubo; +} MTLUniformBufferBinding; + typedef struct MTLContextGlobalShaderPipelineState { - /* ..TODO(Metal): More elements to be added as backend fleshed out.. */ + bool initialised; + + /* Whether the pipeline state has been modified since application. + * `dirty_flags` is a bitmask of the types of state which have been updated. + * This is in order to optimize calls and only re-apply state as needed. + * Some state parameters are dynamically applied on the RenderCommandEncoder, + * others may be encapsulated in GPU-resident state objects such as + * MTLDepthStencilState or MTLRenderPipelineState. */ + bool dirty; + MTLPipelineStateDirtyFlag dirty_flags; + + /* Shader resources. */ + MTLShader *null_shader; + + /* Active Shader State. */ + MTLShader *active_shader; + + /* Global Uniform Buffers. */ + MTLUniformBufferBinding ubo_bindings[MTL_MAX_UNIFORM_BUFFER_BINDINGS]; + + /* Context Texture bindings. */ + MTLTextureBinding texture_bindings[MTL_MAX_TEXTURE_SLOTS]; + MTLSamplerBinding sampler_bindings[MTL_MAX_SAMPLER_SLOTS]; + + /*** --- Render Pipeline State --- ***/ + /* Track global render pipeline state for the current context. The functions in GPU_state.h + * modify these parameters. Certain values, tagged [PSO], are parameters which are required to be + * passed into PSO creation, rather than dynamic state functions on the RenderCommandEncoder. + */ - /*** DATA and IMAGE access state ***/ + /* Blending State. */ + MTLColorWriteMask color_write_mask; /* [PSO] */ + bool blending_enabled; /* [PSO] */ + MTLBlendOperation alpha_blend_op; /* [PSO] */ + MTLBlendOperation rgb_blend_op; /* [PSO] */ + MTLBlendFactor dest_alpha_blend_factor; /* [PSO] */ + MTLBlendFactor dest_rgb_blend_factor; /* [PSO] */ + MTLBlendFactor src_alpha_blend_factor; /* [PSO] */ + MTLBlendFactor src_rgb_blend_factor; /* [PSO] */ + + /* Culling State. */ + bool culling_enabled; + eGPUFaceCullTest cull_mode; + eGPUFrontFace front_face; + + /* Depth State. */ + MTLContextDepthStencilState depth_stencil_state; + + /* Viewport/Scissor Region. */ + int viewport_offset_x; + int viewport_offset_y; + int viewport_width; + int viewport_height; + bool scissor_enabled; + int scissor_x; + int scissor_y; + int scissor_width; + int scissor_height; + + /* Image data access state. */ uint unpack_row_length; + + /* Render parameters. */ + float point_size = 1.0f; + float line_width = 1.0f; + } MTLContextGlobalShaderPipelineState; /* Metal Buffer */ @@ -127,8 +373,8 @@ typedef struct MTLTemporaryBufferRange { bool requires_flush(); } MTLTemporaryBufferRange; -/** MTLContext -- Core render loop and state management **/ -/* Note(Metal): Partial MTLContext stub to provide wrapper functionality +/** MTLContext -- Core render loop and state management. **/ +/* NOTE(Metal): Partial MTLContext stub to provide wrapper functionality * for work-in-progress MTL* classes. */ class MTLContext : public Context { @@ -138,8 +384,24 @@ class MTLContext : public Context { /* Compute and specialization caches. */ MTLContextTextureUtils texture_utils_; + /* Texture Samplers. */ + /* Cache of generated MTLSamplerState objects based on permutations of `eGPUSamplerState`. */ + id<MTLSamplerState> sampler_state_cache_[GPU_SAMPLER_MAX] = {0}; + id<MTLSamplerState> default_sampler_state_ = nil; + + /* When texture sampler count exceeds the resource bind limit, an + * argument buffer is used to pass samplers to the shader. + * Each unique configurations of multiple samplers can be cached, so as to not require + * re-generation. `samplers_` stores the current list of bound sampler objects. + * `cached_sampler_buffers_` is a cache of encoded argument buffers which can be re-used. */ + MTLSamplerArray samplers_; + blender::Map<MTLSamplerArray, gpu::MTLBuffer *> cached_sampler_buffers_; + public: - /* METAL API Resource Handles. */ + /* Shaders and Pipeline state. */ + MTLContextGlobalShaderPipelineState pipeline_state; + + /* Metal API Resource Handles. */ id<MTLCommandQueue> queue = nil; id<MTLDevice> device = nil; @@ -160,24 +422,40 @@ class MTLContext : public Context { void debug_group_begin(const char *name, int index) override; void debug_group_end(void) override; - /*** Context Utility functions */ + /*** MTLContext Utility functions. */ /* * All below functions modify the global state for the context, controlling the flow of * rendering, binding resources, setting global state, resource management etc; */ - /* Metal Context Core functions */ - /* Command Buffer Management */ + /* Metal Context Core functions. */ + /* Command Buffer Management. */ id<MTLCommandBuffer> get_active_command_buffer(); - /* Render Pass State and Management */ + /* Render Pass State and Management. */ void begin_render_pass(); void end_render_pass(); - - /* Shaders and Pipeline state */ - MTLContextGlobalShaderPipelineState pipeline_state; - - /* Texture utilities */ + bool is_render_pass_active(); + + /* Texture Binding. */ + void texture_bind(gpu::MTLTexture *mtl_texture, unsigned int texture_unit); + void sampler_bind(MTLSamplerState, unsigned int sampler_unit); + void texture_unbind(gpu::MTLTexture *mtl_texture); + void texture_unbind_all(void); + id<MTLSamplerState> get_sampler_from_state(MTLSamplerState state); + id<MTLSamplerState> generate_sampler_from_state(MTLSamplerState state); + id<MTLSamplerState> get_default_sampler_state(); + + /* Metal Context pipeline state. */ + void pipeline_state_init(void); + MTLShader *get_active_shader(void); + + /* State assignment. */ + void set_viewport(int origin_x, int origin_y, int width, int height); + void set_scissor(int scissor_x, int scissor_y, int scissor_width, int scissor_height); + void set_scissor_enabled(bool scissor_enabled); + + /* Texture utilities. */ MTLContextTextureUtils &get_texture_utils() { return this->texture_utils_; diff --git a/source/blender/gpu/metal/mtl_context.mm b/source/blender/gpu/metal/mtl_context.mm index 18ed38c373d..94f5682b11b 100644 --- a/source/blender/gpu/metal/mtl_context.mm +++ b/source/blender/gpu/metal/mtl_context.mm @@ -5,6 +5,11 @@ */ #include "mtl_context.hh" #include "mtl_debug.hh" +#include "mtl_state.hh" + +#include "DNA_userdef_types.h" + +#include "GPU_capabilities.h" using namespace blender; using namespace blender::gpu; @@ -44,6 +49,9 @@ MTLContext::MTLContext(void *ghost_window) /* Init debug. */ debug::mtl_debug_init(); + /* Initialize Metal modules. */ + this->state_manager = new MTLStateManager(this); + /* TODO(Metal): Implement. */ } @@ -98,6 +106,234 @@ void MTLContext::end_render_pass() /* TODO(Metal): Implement. */ } +bool MTLContext::is_render_pass_active() +{ + /* TODO(Metal): Implement. */ + return false; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Global Context State + * \{ */ + +/* Metal Context Pipeline State. */ +void MTLContext::pipeline_state_init() +{ + /*** Initialize state only once. ***/ + if (!this->pipeline_state.initialised) { + this->pipeline_state.initialised = true; + this->pipeline_state.active_shader = NULL; + + /* Clear bindings state. */ + for (int t = 0; t < GPU_max_textures(); t++) { + this->pipeline_state.texture_bindings[t].used = false; + this->pipeline_state.texture_bindings[t].texture_slot_index = t; + this->pipeline_state.texture_bindings[t].texture_resource = NULL; + } + for (int s = 0; s < MTL_MAX_SAMPLER_SLOTS; s++) { + this->pipeline_state.sampler_bindings[s].used = false; + } + for (int u = 0; u < MTL_MAX_UNIFORM_BUFFER_BINDINGS; u++) { + this->pipeline_state.ubo_bindings[u].bound = false; + this->pipeline_state.ubo_bindings[u].ubo = NULL; + } + } + + /*** State defaults -- restored by GPU_state_init. ***/ + /* Clear blending State. */ + this->pipeline_state.color_write_mask = MTLColorWriteMaskRed | MTLColorWriteMaskGreen | + MTLColorWriteMaskBlue | MTLColorWriteMaskAlpha; + this->pipeline_state.blending_enabled = false; + this->pipeline_state.alpha_blend_op = MTLBlendOperationAdd; + this->pipeline_state.rgb_blend_op = MTLBlendOperationAdd; + this->pipeline_state.dest_alpha_blend_factor = MTLBlendFactorZero; + this->pipeline_state.dest_rgb_blend_factor = MTLBlendFactorZero; + this->pipeline_state.src_alpha_blend_factor = MTLBlendFactorOne; + this->pipeline_state.src_rgb_blend_factor = MTLBlendFactorOne; + + /* Viewport and scissor. */ + this->pipeline_state.viewport_offset_x = 0; + this->pipeline_state.viewport_offset_y = 0; + this->pipeline_state.viewport_width = 0; + this->pipeline_state.viewport_height = 0; + this->pipeline_state.scissor_x = 0; + this->pipeline_state.scissor_y = 0; + this->pipeline_state.scissor_width = 0; + this->pipeline_state.scissor_height = 0; + this->pipeline_state.scissor_enabled = false; + + /* Culling State. */ + this->pipeline_state.culling_enabled = false; + this->pipeline_state.cull_mode = GPU_CULL_NONE; + this->pipeline_state.front_face = GPU_COUNTERCLOCKWISE; + + /* DATA and IMAGE access state. */ + this->pipeline_state.unpack_row_length = 0; + + /* Depth State. */ + this->pipeline_state.depth_stencil_state.depth_write_enable = false; + this->pipeline_state.depth_stencil_state.depth_test_enabled = false; + this->pipeline_state.depth_stencil_state.depth_range_near = 0.0; + this->pipeline_state.depth_stencil_state.depth_range_far = 1.0; + this->pipeline_state.depth_stencil_state.depth_function = MTLCompareFunctionAlways; + this->pipeline_state.depth_stencil_state.depth_bias = 0.0; + this->pipeline_state.depth_stencil_state.depth_slope_scale = 0.0; + this->pipeline_state.depth_stencil_state.depth_bias_enabled_for_points = false; + this->pipeline_state.depth_stencil_state.depth_bias_enabled_for_lines = false; + this->pipeline_state.depth_stencil_state.depth_bias_enabled_for_tris = false; + + /* Stencil State. */ + this->pipeline_state.depth_stencil_state.stencil_test_enabled = false; + this->pipeline_state.depth_stencil_state.stencil_read_mask = 0xFF; + this->pipeline_state.depth_stencil_state.stencil_write_mask = 0xFF; + this->pipeline_state.depth_stencil_state.stencil_ref = 0; + this->pipeline_state.depth_stencil_state.stencil_func = MTLCompareFunctionAlways; + this->pipeline_state.depth_stencil_state.stencil_op_front_stencil_fail = MTLStencilOperationKeep; + this->pipeline_state.depth_stencil_state.stencil_op_front_depth_fail = MTLStencilOperationKeep; + this->pipeline_state.depth_stencil_state.stencil_op_front_depthstencil_pass = + MTLStencilOperationKeep; + this->pipeline_state.depth_stencil_state.stencil_op_back_stencil_fail = MTLStencilOperationKeep; + this->pipeline_state.depth_stencil_state.stencil_op_back_depth_fail = MTLStencilOperationKeep; + this->pipeline_state.depth_stencil_state.stencil_op_back_depthstencil_pass = + MTLStencilOperationKeep; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Texture State Management + * \{ */ + +void MTLContext::texture_bind(gpu::MTLTexture *mtl_texture, unsigned int texture_unit) +{ + BLI_assert(this); + BLI_assert(mtl_texture); + + if (texture_unit < 0 || texture_unit >= GPU_max_textures() || + texture_unit >= MTL_MAX_TEXTURE_SLOTS) { + MTL_LOG_WARNING("Attempting to bind texture '%s' to invalid texture unit %d\n", + mtl_texture->get_name(), + texture_unit); + BLI_assert(false); + return; + } + + /* Bind new texture. */ + this->pipeline_state.texture_bindings[texture_unit].texture_resource = mtl_texture; + this->pipeline_state.texture_bindings[texture_unit].used = true; + mtl_texture->is_bound_ = true; +} + +void MTLContext::sampler_bind(MTLSamplerState sampler_state, unsigned int sampler_unit) +{ + BLI_assert(this); + if (sampler_unit < 0 || sampler_unit >= GPU_max_textures() || + sampler_unit >= MTL_MAX_SAMPLER_SLOTS) { + MTL_LOG_WARNING("Attempting to bind sampler to invalid sampler unit %d\n", sampler_unit); + BLI_assert(false); + return; + } + + /* Apply binding. */ + this->pipeline_state.sampler_bindings[sampler_unit] = {true, sampler_state}; +} + +void MTLContext::texture_unbind(gpu::MTLTexture *mtl_texture) +{ + BLI_assert(mtl_texture); + + /* Iterate through textures in state and unbind. */ + for (int i = 0; i < min_uu(GPU_max_textures(), MTL_MAX_TEXTURE_SLOTS); i++) { + if (this->pipeline_state.texture_bindings[i].texture_resource == mtl_texture) { + this->pipeline_state.texture_bindings[i].texture_resource = nullptr; + this->pipeline_state.texture_bindings[i].used = false; + } + } + + /* Locally unbind texture. */ + mtl_texture->is_bound_ = false; +} + +void MTLContext::texture_unbind_all() +{ + /* Iterate through context's bound textures. */ + for (int t = 0; t < min_uu(GPU_max_textures(), MTL_MAX_TEXTURE_SLOTS); t++) { + if (this->pipeline_state.texture_bindings[t].used && + this->pipeline_state.texture_bindings[t].texture_resource) { + + this->pipeline_state.texture_bindings[t].used = false; + this->pipeline_state.texture_bindings[t].texture_resource = nullptr; + } + } +} + +id<MTLSamplerState> MTLContext::get_sampler_from_state(MTLSamplerState sampler_state) +{ + BLI_assert((unsigned int)sampler_state >= 0 && ((unsigned int)sampler_state) < GPU_SAMPLER_MAX); + return this->sampler_state_cache_[(unsigned int)sampler_state]; +} + +id<MTLSamplerState> MTLContext::generate_sampler_from_state(MTLSamplerState sampler_state) +{ + /* Check if sampler already exists for given state. */ + id<MTLSamplerState> st = this->sampler_state_cache_[(unsigned int)sampler_state]; + if (st != nil) { + return st; + } + else { + MTLSamplerDescriptor *descriptor = [[MTLSamplerDescriptor alloc] init]; + descriptor.normalizedCoordinates = true; + + MTLSamplerAddressMode clamp_type = (sampler_state.state & GPU_SAMPLER_CLAMP_BORDER) ? + MTLSamplerAddressModeClampToBorderColor : + MTLSamplerAddressModeClampToEdge; + descriptor.rAddressMode = (sampler_state.state & GPU_SAMPLER_REPEAT_R) ? + MTLSamplerAddressModeRepeat : + clamp_type; + descriptor.sAddressMode = (sampler_state.state & GPU_SAMPLER_REPEAT_S) ? + MTLSamplerAddressModeRepeat : + clamp_type; + descriptor.tAddressMode = (sampler_state.state & GPU_SAMPLER_REPEAT_T) ? + MTLSamplerAddressModeRepeat : + clamp_type; + descriptor.borderColor = MTLSamplerBorderColorTransparentBlack; + descriptor.minFilter = (sampler_state.state & GPU_SAMPLER_FILTER) ? + MTLSamplerMinMagFilterLinear : + MTLSamplerMinMagFilterNearest; + descriptor.magFilter = (sampler_state.state & GPU_SAMPLER_FILTER) ? + MTLSamplerMinMagFilterLinear : + MTLSamplerMinMagFilterNearest; + descriptor.mipFilter = (sampler_state.state & GPU_SAMPLER_MIPMAP) ? + MTLSamplerMipFilterLinear : + MTLSamplerMipFilterNotMipmapped; + descriptor.lodMinClamp = -1000; + descriptor.lodMaxClamp = 1000; + float aniso_filter = max_ff(16, U.anisotropic_filter); + descriptor.maxAnisotropy = (sampler_state.state & GPU_SAMPLER_MIPMAP) ? aniso_filter : 1; + descriptor.compareFunction = (sampler_state.state & GPU_SAMPLER_COMPARE) ? + MTLCompareFunctionLessEqual : + MTLCompareFunctionAlways; + descriptor.supportArgumentBuffers = true; + + id<MTLSamplerState> state = [this->device newSamplerStateWithDescriptor:descriptor]; + this->sampler_state_cache_[(unsigned int)sampler_state] = state; + + BLI_assert(state != nil); + [descriptor autorelease]; + return state; + } +} + +id<MTLSamplerState> MTLContext::get_default_sampler_state() +{ + if (this->default_sampler_state_ == nil) { + this->default_sampler_state_ = this->get_sampler_from_state(DEFAULT_SAMPLER_STATE); + } + return this->default_sampler_state_; +} + /** \} */ } // blender::gpu diff --git a/source/blender/gpu/metal/mtl_state.hh b/source/blender/gpu/metal/mtl_state.hh new file mode 100644 index 00000000000..f2d85f9648b --- /dev/null +++ b/source/blender/gpu/metal/mtl_state.hh @@ -0,0 +1,73 @@ +/** \file + * \ingroup gpu + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" + +#include "GPU_state.h" +#include "gpu_state_private.hh" + +namespace blender::gpu { + +/* Forward Declarations. */ +class MTLContext; + +/** + * State manager keeping track of the draw state and applying it before drawing. + * Metal Implementation. + **/ +class MTLStateManager : public StateManager { + public: + private: + /* Current state of the associated MTLContext. + * Avoids resetting the whole state for every change. */ + GPUState current_; + GPUStateMutable current_mutable_; + MTLContext *context_; + + public: + MTLStateManager(MTLContext *ctx); + + 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; + + private: + void set_write_mask(const eGPUWriteMask value); + void set_depth_test(const eGPUDepthTest value); + void set_stencil_test(const eGPUStencilTest test, const eGPUStencilOp operation); + void set_stencil_mask(const eGPUStencilTest test, const GPUStateMutable state); + void set_clip_distances(const int new_dist_len, const int old_dist_len); + void set_logic_op(const bool enable); + void set_facing(const bool invert); + void set_backface_culling(const eGPUFaceCullTest test); + void set_provoking_vert(const eGPUProvokingVertex vert); + void set_shadow_bias(const bool enable); + void set_blend(const eGPUBlend value); + + void set_state(const GPUState &state); + void set_mutable_state(const GPUStateMutable &state); + + /* METAL State utility functions. */ + void mtl_state_init(void); + void mtl_depth_range(float near, float far); + void mtl_stencil_mask(unsigned int mask); + void mtl_stencil_set_func(eGPUStencilTest stencil_func, int ref, unsigned int mask); + + MEM_CXX_CLASS_ALLOC_FUNCS("MTLStateManager") +}; + +} // namespace blender::gpu diff --git a/source/blender/gpu/metal/mtl_state.mm b/source/blender/gpu/metal/mtl_state.mm new file mode 100644 index 00000000000..5f52bc55f72 --- /dev/null +++ b/source/blender/gpu/metal/mtl_state.mm @@ -0,0 +1,675 @@ +/** \file + * \ingroup gpu + */ + +#include "BLI_math_base.h" +#include "BLI_math_bits.h" + +#include "GPU_framebuffer.h" + +#include "mtl_context.hh" +#include "mtl_state.hh" + +namespace blender::gpu { + +/* -------------------------------------------------------------------- */ +/** \name MTLStateManager + * \{ */ + +void MTLStateManager::mtl_state_init(void) +{ + BLI_assert(this->context_); + this->context_->pipeline_state_init(); +} + +MTLStateManager::MTLStateManager(MTLContext *ctx) : StateManager() +{ + /* Initialize State. */ + this->context_ = ctx; + mtl_state_init(); + + /* Force update using default state. */ + current_ = ~state; + current_mutable_ = ~mutable_state; + set_state(state); + set_mutable_state(mutable_state); +} + +void MTLStateManager::apply_state(void) +{ + this->set_state(this->state); + this->set_mutable_state(this->mutable_state); + /* TODO(Metal): Enable after integration of MTLFrameBuffer. */ + /* static_cast<MTLFrameBuffer *>(this->context_->active_fb)->apply_state(); */ +}; + +void MTLStateManager::force_state(void) +{ + /* Little exception for clip distances since they need to keep the old count correct. */ + uint32_t clip_distances = current_.clip_distances; + current_ = ~this->state; + current_.clip_distances = clip_distances; + current_mutable_ = ~this->mutable_state; + this->set_state(this->state); + this->set_mutable_state(this->mutable_state); +}; + +void MTLStateManager::set_state(const GPUState &state) +{ + GPUState changed = state ^ current_; + + if (changed.blend != 0) { + set_blend((eGPUBlend)state.blend); + } + if (changed.write_mask != 0) { + set_write_mask((eGPUWriteMask)state.write_mask); + } + if (changed.depth_test != 0) { + set_depth_test((eGPUDepthTest)state.depth_test); + } + if (changed.stencil_test != 0 || changed.stencil_op != 0) { + set_stencil_test((eGPUStencilTest)state.stencil_test, (eGPUStencilOp)state.stencil_op); + set_stencil_mask((eGPUStencilTest)state.stencil_test, mutable_state); + } + if (changed.clip_distances != 0) { + set_clip_distances(state.clip_distances, current_.clip_distances); + } + if (changed.culling_test != 0) { + set_backface_culling((eGPUFaceCullTest)state.culling_test); + } + if (changed.logic_op_xor != 0) { + set_logic_op(state.logic_op_xor); + } + if (changed.invert_facing != 0) { + set_facing(state.invert_facing); + } + if (changed.provoking_vert != 0) { + set_provoking_vert((eGPUProvokingVertex)state.provoking_vert); + } + if (changed.shadow_bias != 0) { + set_shadow_bias(state.shadow_bias); + } + + /* TODO remove (Following GLState). */ + if (changed.polygon_smooth) { + /* NOTE: Unsupported in Metal. */ + } + if (changed.line_smooth) { + /* NOTE: Unsupported in Metal. */ + } + + current_ = state; +} + +void MTLStateManager::mtl_depth_range(float near, float far) +{ + BLI_assert(this->context_); + BLI_assert(near >= 0.0 && near < 1.0); + BLI_assert(far > 0.0 && far <= 1.0); + MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state; + MTLContextDepthStencilState &ds_state = pipeline_state.depth_stencil_state; + + ds_state.depth_range_near = near; + ds_state.depth_range_far = far; + pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_VIEWPORT_FLAG; +} + +void MTLStateManager::set_mutable_state(const GPUStateMutable &state) +{ + GPUStateMutable changed = state ^ current_mutable_; + MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state; + + if (float_as_uint(changed.point_size) != 0) { + pipeline_state.point_size = state.point_size; + pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_PSO_FLAG; + } + + if (changed.line_width != 0) { + pipeline_state.line_width = state.line_width; + pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_PSO_FLAG; + } + + if (changed.depth_range[0] != 0 || changed.depth_range[1] != 0) { + /* TODO remove, should modify the projection matrix instead. */ + mtl_depth_range(state.depth_range[0], state.depth_range[1]); + } + + if (changed.stencil_compare_mask != 0 || changed.stencil_reference != 0 || + changed.stencil_write_mask != 0) { + set_stencil_mask((eGPUStencilTest)current_.stencil_test, state); + } + + current_mutable_ = state; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name State setting functions + * \{ */ + +void MTLStateManager::set_write_mask(const eGPUWriteMask value) +{ + BLI_assert(this->context_); + MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state; + pipeline_state.depth_stencil_state.depth_write_enable = ((value & GPU_WRITE_DEPTH) != 0); + pipeline_state.color_write_mask = + (((value & GPU_WRITE_RED) != 0) ? MTLColorWriteMaskRed : MTLColorWriteMaskNone) | + (((value & GPU_WRITE_GREEN) != 0) ? MTLColorWriteMaskGreen : MTLColorWriteMaskNone) | + (((value & GPU_WRITE_BLUE) != 0) ? MTLColorWriteMaskBlue : MTLColorWriteMaskNone) | + (((value & GPU_WRITE_ALPHA) != 0) ? MTLColorWriteMaskAlpha : MTLColorWriteMaskNone); + pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_PSO_FLAG; +} + +static MTLCompareFunction gpu_depth_function_to_metal(eGPUDepthTest depth_func) +{ + switch (depth_func) { + case GPU_DEPTH_NONE: + return MTLCompareFunctionNever; + case GPU_DEPTH_LESS: + return MTLCompareFunctionLess; + case GPU_DEPTH_EQUAL: + return MTLCompareFunctionEqual; + case GPU_DEPTH_LESS_EQUAL: + return MTLCompareFunctionLessEqual; + case GPU_DEPTH_GREATER: + return MTLCompareFunctionGreater; + case GPU_DEPTH_GREATER_EQUAL: + return MTLCompareFunctionGreaterEqual; + case GPU_DEPTH_ALWAYS: + return MTLCompareFunctionAlways; + default: + BLI_assert(false && "Invalid eGPUDepthTest"); + break; + } + return MTLCompareFunctionAlways; +} + +static MTLCompareFunction gpu_stencil_func_to_metal(eGPUStencilTest stencil_func) +{ + switch (stencil_func) { + case GPU_STENCIL_NONE: + return MTLCompareFunctionAlways; + case GPU_STENCIL_EQUAL: + return MTLCompareFunctionEqual; + case GPU_STENCIL_NEQUAL: + return MTLCompareFunctionNotEqual; + case GPU_STENCIL_ALWAYS: + return MTLCompareFunctionAlways; + default: + BLI_assert(false && "Unrecognised eGPUStencilTest function"); + break; + } + return MTLCompareFunctionAlways; +} + +void MTLStateManager::set_depth_test(const eGPUDepthTest value) +{ + BLI_assert(this->context_); + MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state; + MTLContextDepthStencilState &ds_state = pipeline_state.depth_stencil_state; + + ds_state.depth_test_enabled = (value != GPU_DEPTH_NONE); + ds_state.depth_function = gpu_depth_function_to_metal(value); + pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_DEPTHSTENCIL_FLAG; +} + +void MTLStateManager::mtl_stencil_mask(unsigned int mask) +{ + BLI_assert(this->context_); + MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state; + pipeline_state.depth_stencil_state.stencil_write_mask = mask; + pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_DEPTHSTENCIL_FLAG; +} + +void MTLStateManager::mtl_stencil_set_func(eGPUStencilTest stencil_func, + int ref, + unsigned int mask) +{ + BLI_assert(this->context_); + MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state; + MTLContextDepthStencilState &ds_state = pipeline_state.depth_stencil_state; + + ds_state.stencil_func = gpu_stencil_func_to_metal(stencil_func); + ds_state.stencil_ref = ref; + ds_state.stencil_read_mask = mask; + pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_DEPTHSTENCIL_FLAG; +} + +static void mtl_stencil_set_op_separate(MTLContext *context, + eGPUFaceCullTest face, + MTLStencilOperation stencil_fail, + MTLStencilOperation depth_test_fail, + MTLStencilOperation depthstencil_pass) +{ + BLI_assert(context); + MTLContextGlobalShaderPipelineState &pipeline_state = context->pipeline_state; + MTLContextDepthStencilState &ds_state = pipeline_state.depth_stencil_state; + + if (face == GPU_CULL_FRONT) { + ds_state.stencil_op_front_stencil_fail = stencil_fail; + ds_state.stencil_op_front_depth_fail = depth_test_fail; + ds_state.stencil_op_front_depthstencil_pass = depthstencil_pass; + } + else if (face == GPU_CULL_BACK) { + ds_state.stencil_op_back_stencil_fail = stencil_fail; + ds_state.stencil_op_back_depth_fail = depth_test_fail; + ds_state.stencil_op_back_depthstencil_pass = depthstencil_pass; + } + + pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_DEPTHSTENCIL_FLAG; +} + +static void mtl_stencil_set_op(MTLContext *context, + MTLStencilOperation stencil_fail, + MTLStencilOperation depth_test_fail, + MTLStencilOperation depthstencil_pass) +{ + mtl_stencil_set_op_separate( + context, GPU_CULL_FRONT, stencil_fail, depth_test_fail, depthstencil_pass); + mtl_stencil_set_op_separate( + context, GPU_CULL_BACK, stencil_fail, depth_test_fail, depthstencil_pass); +} + +void MTLStateManager::set_stencil_test(const eGPUStencilTest test, const eGPUStencilOp operation) +{ + switch (operation) { + case GPU_STENCIL_OP_REPLACE: + mtl_stencil_set_op(this->context_, + MTLStencilOperationKeep, + MTLStencilOperationKeep, + MTLStencilOperationReplace); + break; + case GPU_STENCIL_OP_COUNT_DEPTH_PASS: + /* Winding inversed due to flipped Y coordinate system in Metal. */ + mtl_stencil_set_op_separate(this->context_, + GPU_CULL_FRONT, + MTLStencilOperationKeep, + MTLStencilOperationKeep, + MTLStencilOperationIncrementWrap); + mtl_stencil_set_op_separate(this->context_, + GPU_CULL_BACK, + MTLStencilOperationKeep, + MTLStencilOperationKeep, + MTLStencilOperationDecrementWrap); + break; + case GPU_STENCIL_OP_COUNT_DEPTH_FAIL: + /* Winding inversed due to flipped Y coordinate system in Metal. */ + mtl_stencil_set_op_separate(this->context_, + GPU_CULL_FRONT, + MTLStencilOperationKeep, + MTLStencilOperationDecrementWrap, + MTLStencilOperationKeep); + mtl_stencil_set_op_separate(this->context_, + GPU_CULL_BACK, + MTLStencilOperationKeep, + MTLStencilOperationIncrementWrap, + MTLStencilOperationKeep); + break; + case GPU_STENCIL_OP_NONE: + default: + mtl_stencil_set_op(this->context_, + MTLStencilOperationKeep, + MTLStencilOperationKeep, + MTLStencilOperationKeep); + } + + BLI_assert(this->context_); + MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state; + pipeline_state.depth_stencil_state.stencil_test_enabled = (test != GPU_STENCIL_NONE); + pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_DEPTHSTENCIL_FLAG; +} + +void MTLStateManager::set_stencil_mask(const eGPUStencilTest test, const GPUStateMutable state) +{ + if (test == GPU_STENCIL_NONE) { + mtl_stencil_mask(0x00); + mtl_stencil_set_func(GPU_STENCIL_ALWAYS, 0x00, 0x00); + } + else { + mtl_stencil_mask(state.stencil_write_mask); + mtl_stencil_set_func(test, state.stencil_reference, state.stencil_compare_mask); + } +} + +void MTLStateManager::set_clip_distances(const int new_dist_len, const int old_dist_len) +{ + /* TODO(Metal): Support Clip distances in METAL. Clip distance + * assignment via shader is supported, but global clip-states require + * support. */ +} + +void MTLStateManager::set_logic_op(const bool enable) +{ + /* NOTE(Metal): Logic Operations not directly supported. */ +} + +void MTLStateManager::set_facing(const bool invert) +{ + /* Check Current Context. */ + BLI_assert(this->context_); + MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state; + + /* Apply State -- opposite of GL, as METAL default is GPU_CLOCKWISE, GL default is + * COUNTERCLOCKWISE. This needs to be the inverse of the default. */ + pipeline_state.front_face = (invert) ? GPU_COUNTERCLOCKWISE : GPU_CLOCKWISE; + + /* Mark Dirty - Ensure context updates state between draws. */ + pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_FRONT_FACING_FLAG; + pipeline_state.dirty = true; +} + +void MTLStateManager::set_backface_culling(const eGPUFaceCullTest test) +{ + /* Check Current Context. */ + BLI_assert(this->context_); + MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state; + + /* Apply State. */ + pipeline_state.culling_enabled = (test != GPU_CULL_NONE); + pipeline_state.cull_mode = test; + + /* Mark Dirty - Ensure context updates state between draws. */ + pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_CULLMODE_FLAG; + pipeline_state.dirty = true; +} + +void MTLStateManager::set_provoking_vert(const eGPUProvokingVertex vert) +{ + /* NOTE(Metal): Provoking vertex is not a feature in the Metal API. + * Shaders are handled on a case-by-case basis using a modified vertex shader. + * For example, wireframe rendering and edit-mesh shaders utilize an SSBO-based + * vertex fetching mechanism which considers the inverse convention for flat + * shading, to ensure consistent results with OpenGL. */ +} + +void MTLStateManager::set_shadow_bias(const bool enable) +{ + /* Check Current Context. */ + BLI_assert(this->context_); + MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state; + MTLContextDepthStencilState &ds_state = pipeline_state.depth_stencil_state; + + /* Apply State. */ + if (enable) { + ds_state.depth_bias_enabled_for_lines = true; + ds_state.depth_bias_enabled_for_tris = true; + ds_state.depth_bias = 2.0f; + ds_state.depth_slope_scale = 1.0f; + } + else { + ds_state.depth_bias_enabled_for_lines = false; + ds_state.depth_bias_enabled_for_tris = false; + ds_state.depth_bias = 0.0f; + ds_state.depth_slope_scale = 0.0f; + } + + /* Mark Dirty - Ensure context updates depth-stencil state between draws. */ + pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_DEPTHSTENCIL_FLAG; + pipeline_state.dirty = true; +} + +void MTLStateManager::set_blend(const eGPUBlend value) +{ + /** + * Factors to the equation. + * SRC is fragment shader output. + * DST is framebuffer color. + * final.rgb = SRC.rgb * src_rgb + DST.rgb * dst_rgb; + * final.a = SRC.a * src_alpha + DST.a * dst_alpha; + **/ + MTLBlendFactor src_rgb; + MTLBlendFactor dst_rgb; + MTLBlendFactor src_alpha; + MTLBlendFactor dst_alpha; + switch (value) { + default: + case GPU_BLEND_ALPHA: { + src_rgb = MTLBlendFactorSourceAlpha; + dst_rgb = MTLBlendFactorOneMinusSourceAlpha; + src_alpha = MTLBlendFactorOne; + dst_alpha = MTLBlendFactorOneMinusSourceAlpha; + break; + } + case GPU_BLEND_ALPHA_PREMULT: { + src_rgb = MTLBlendFactorOne; + dst_rgb = MTLBlendFactorOneMinusSourceAlpha; + src_alpha = MTLBlendFactorOne; + dst_alpha = MTLBlendFactorOneMinusSourceAlpha; + break; + } + case GPU_BLEND_ADDITIVE: { + /* Do not let alpha accumulate but pre-multiply the source RGB by it. */ + src_rgb = MTLBlendFactorSourceAlpha; + dst_rgb = MTLBlendFactorOne; + src_alpha = MTLBlendFactorZero; + dst_alpha = MTLBlendFactorOne; + break; + } + case GPU_BLEND_SUBTRACT: + case GPU_BLEND_ADDITIVE_PREMULT: { + /* Let alpha accumulate. */ + src_rgb = MTLBlendFactorOne; + dst_rgb = MTLBlendFactorOne; + src_alpha = MTLBlendFactorOne; + dst_alpha = MTLBlendFactorOne; + break; + } + case GPU_BLEND_MULTIPLY: { + src_rgb = MTLBlendFactorDestinationColor; + dst_rgb = MTLBlendFactorZero; + src_alpha = MTLBlendFactorDestinationAlpha; + dst_alpha = MTLBlendFactorZero; + break; + } + case GPU_BLEND_INVERT: { + src_rgb = MTLBlendFactorOneMinusDestinationColor; + dst_rgb = MTLBlendFactorZero; + src_alpha = MTLBlendFactorZero; + dst_alpha = MTLBlendFactorOne; + break; + } + case GPU_BLEND_OIT: { + src_rgb = MTLBlendFactorOne; + dst_rgb = MTLBlendFactorOne; + src_alpha = MTLBlendFactorZero; + dst_alpha = MTLBlendFactorOneMinusSourceAlpha; + break; + } + case GPU_BLEND_BACKGROUND: { + src_rgb = MTLBlendFactorOneMinusDestinationAlpha; + dst_rgb = MTLBlendFactorSourceAlpha; + src_alpha = MTLBlendFactorZero; + dst_alpha = MTLBlendFactorSourceAlpha; + break; + } + case GPU_BLEND_ALPHA_UNDER_PREMUL: { + src_rgb = MTLBlendFactorOneMinusDestinationAlpha; + dst_rgb = MTLBlendFactorOne; + src_alpha = MTLBlendFactorOneMinusDestinationAlpha; + dst_alpha = MTLBlendFactorOne; + break; + } + case GPU_BLEND_CUSTOM: { + src_rgb = MTLBlendFactorOne; + dst_rgb = MTLBlendFactorSource1Color; + src_alpha = MTLBlendFactorOne; + dst_alpha = MTLBlendFactorSource1Alpha; + break; + } + } + + /* Check Current Context. */ + BLI_assert(this->context_); + MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state; + + if (value == GPU_BLEND_SUBTRACT) { + pipeline_state.rgb_blend_op = MTLBlendOperationReverseSubtract; + pipeline_state.alpha_blend_op = MTLBlendOperationReverseSubtract; + } + else { + pipeline_state.rgb_blend_op = MTLBlendOperationAdd; + pipeline_state.alpha_blend_op = MTLBlendOperationAdd; + } + + /* Apply State. */ + pipeline_state.blending_enabled = (value != GPU_BLEND_NONE); + pipeline_state.src_rgb_blend_factor = src_rgb; + pipeline_state.dest_rgb_blend_factor = dst_rgb; + pipeline_state.src_alpha_blend_factor = src_alpha; + pipeline_state.dest_alpha_blend_factor = dst_alpha; + + /* Mark Dirty - Ensure context updates PSOs between draws. */ + pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_PSO_FLAG; + pipeline_state.dirty = true; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Memory barrier + * \{ */ + +/* NOTE(Metal): Granular option for specifying before/after stages for a barrier + * Would be a useful feature. */ +/*void MTLStateManager::issue_barrier(eGPUBarrier barrier_bits, + eGPUStageBarrierBits before_stages, + eGPUStageBarrierBits after_stages) */ +void MTLStateManager::issue_barrier(eGPUBarrier barrier_bits) +{ + /* NOTE(Metal): The Metal API implicitly tracks dependencies between resources. + * Memory barriers and execution barriers (Fences/Events) can be used to coordinate + * this explicitly, however, in most cases, the driver will be able to + * resolve these dependencies automatically. + * For untracked resources, such as MTLHeap's, explicit barriers are necessary. */ + eGPUStageBarrierBits before_stages = GPU_BARRIER_STAGE_ANY; + eGPUStageBarrierBits after_stages = GPU_BARRIER_STAGE_ANY; + + MTLContext *ctx = reinterpret_cast<MTLContext *>(GPU_context_active_get()); + BLI_assert(ctx); + if (ctx->is_render_pass_active()) { + + /* Apple Silicon does not support memory barriers. + * We do not currently need these due to implicit API guarantees. + * NOTE(Metal): MTLFence/MTLEvent may be required to synchronize work if + * untracked resources are ever used. */ + if ([ctx->device hasUnifiedMemory]) { + return; + } + + /* Issue barrier. */ + /* TODO(Metal): To be completed pending implementation of RenderCommandEncoder management. */ + id<MTLRenderCommandEncoder> rec = nil; // ctx->get_active_render_command_encoder(); + BLI_assert(rec); + + /* Only supporting Metal on 10.15 onward anyway - Check required for warnings. */ + if (@available(macOS 10.14, *)) { + MTLBarrierScope scope = 0; + if (barrier_bits & GPU_BARRIER_SHADER_IMAGE_ACCESS || + barrier_bits & GPU_BARRIER_TEXTURE_FETCH) { + scope = scope | MTLBarrierScopeTextures | MTLBarrierScopeRenderTargets; + } + if (barrier_bits & GPU_BARRIER_SHADER_STORAGE || + barrier_bits & GPU_BARRIER_VERTEX_ATTRIB_ARRAY || + barrier_bits & GPU_BARRIER_ELEMENT_ARRAY) { + scope = scope | MTLBarrierScopeBuffers; + } + + MTLRenderStages before_stage_flags = 0; + MTLRenderStages after_stage_flags = 0; + if (before_stages & GPU_BARRIER_STAGE_VERTEX && + !(before_stages & GPU_BARRIER_STAGE_FRAGMENT)) { + before_stage_flags = before_stage_flags | MTLRenderStageVertex; + } + if (before_stages & GPU_BARRIER_STAGE_FRAGMENT) { + before_stage_flags = before_stage_flags | MTLRenderStageFragment; + } + if (after_stages & GPU_BARRIER_STAGE_VERTEX) { + after_stage_flags = after_stage_flags | MTLRenderStageVertex; + } + if (after_stages & GPU_BARRIER_STAGE_FRAGMENT) { + after_stage_flags = MTLRenderStageFragment; + } + + if (scope != 0) { + [rec memoryBarrierWithScope:scope + afterStages:after_stage_flags + beforeStages:before_stage_flags]; + } + } + } +} +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Texture State Management + * \{ */ + +void MTLStateManager::texture_unpack_row_length_set(uint len) +{ + /* Set source image row data stride when uploading image data to the GPU. */ + MTLContext *ctx = static_cast<MTLContext *>(unwrap(GPU_context_active_get())); + ctx->pipeline_state.unpack_row_length = len; +} + +void MTLStateManager::texture_bind(Texture *tex_, eGPUSamplerState sampler_type, int unit) +{ + BLI_assert(tex_); + gpu::MTLTexture *mtl_tex = static_cast<gpu::MTLTexture *>(tex_); + BLI_assert(mtl_tex); + + MTLContext *ctx = static_cast<MTLContext *>(unwrap(GPU_context_active_get())); + if (unit >= 0) { + ctx->texture_bind(mtl_tex, unit); + + /* Fetching textures default sampler configuration and applying + * eGPUSampler State on top. This path exists to support + * Any of the sampler state which is associated with the + * texture itself such as min/max mip levels. */ + MTLSamplerState sampler = mtl_tex->get_sampler_state(); + sampler.state = sampler_type; + + ctx->sampler_bind(sampler, unit); + } +} + +void MTLStateManager::texture_unbind(Texture *tex_) +{ + BLI_assert(tex_); + gpu::MTLTexture *mtl_tex = static_cast<gpu::MTLTexture *>(tex_); + BLI_assert(mtl_tex); + MTLContext *ctx = static_cast<MTLContext *>(unwrap(GPU_context_active_get())); + ctx->texture_unbind(mtl_tex); +} + +void MTLStateManager::texture_unbind_all(void) +{ + MTLContext *ctx = static_cast<MTLContext *>(unwrap(GPU_context_active_get())); + BLI_assert(ctx); + ctx->texture_unbind_all(); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Image Binding (from image load store) + * \{ */ + +void MTLStateManager::image_bind(Texture *tex_, int unit) +{ + this->texture_bind(tex_, GPU_SAMPLER_DEFAULT, unit); +} + +void MTLStateManager::image_unbind(Texture *tex_) +{ + this->texture_unbind(tex_); +} + +void MTLStateManager::image_unbind_all(void) +{ + this->texture_unbind_all(); +} + +/** \} */ + +} // blender::gpu diff --git a/source/blender/gpu/metal/mtl_texture.hh b/source/blender/gpu/metal/mtl_texture.hh index e013bb5321a..b820256ec36 100644 --- a/source/blender/gpu/metal/mtl_texture.hh +++ b/source/blender/gpu/metal/mtl_texture.hh @@ -47,16 +47,13 @@ struct TextureUpdateRoutineSpecialisation { (component_count_input == other.component_count_input) && (component_count_output == other.component_count_output)); } -}; -template<> struct blender::DefaultHash<TextureUpdateRoutineSpecialisation> { - inline uint64_t operator()(const TextureUpdateRoutineSpecialisation &key) const + inline uint64_t hash() const { - - DefaultHash<std::string> string_hasher; + blender::DefaultHash<std::string> string_hasher; return (uint64_t)string_hasher( - key.input_data_type + key.output_data_type + - std::to_string((key.component_count_input << 8) + key.component_count_output)); + this->input_data_type + this->output_data_type + + std::to_string((this->component_count_input << 8) + this->component_count_output)); } }; @@ -78,12 +75,10 @@ struct DepthTextureUpdateRoutineSpecialisation { { return ((data_mode == other.data_mode)); } -}; -template<> struct blender::DefaultHash<DepthTextureUpdateRoutineSpecialisation> { - inline uint64_t operator()(const DepthTextureUpdateRoutineSpecialisation &key) const + inline uint64_t hash() const { - return (uint64_t)(key.data_mode); + return (uint64_t)(this->data_mode); } }; @@ -109,17 +104,14 @@ struct TextureReadRoutineSpecialisation { (component_count_output == other.component_count_output) && (depth_format_mode == other.depth_format_mode)); } -}; -template<> struct blender::DefaultHash<TextureReadRoutineSpecialisation> { - inline uint64_t operator()(const TextureReadRoutineSpecialisation &key) const + inline uint64_t hash() const { - - DefaultHash<std::string> string_hasher; - return (uint64_t)string_hasher(key.input_data_type + key.output_data_type + - std::to_string((key.component_count_input << 8) + - key.component_count_output + - (key.depth_format_mode << 28))); + blender::DefaultHash<std::string> string_hasher; + return (uint64_t)string_hasher(this->input_data_type + this->output_data_type + + std::to_string((this->component_count_input << 8) + + this->component_count_output + + (this->depth_format_mode << 28))); } }; @@ -158,21 +150,6 @@ typedef struct MTLSamplerState { const MTLSamplerState DEFAULT_SAMPLER_STATE = {GPU_SAMPLER_DEFAULT /*, 0, 9999*/}; -} // namespace blender::gpu - -template<> struct blender::DefaultHash<blender::gpu::MTLSamplerState> { - inline uint64_t operator()(const blender::gpu::MTLSamplerState &key) const - { - const DefaultHash<unsigned int> uint_hasher; - uint64_t main_hash = (uint64_t)uint_hasher((unsigned int)(key.state)); - - /* Hash other parameters as needed. */ - return main_hash; - } -}; - -namespace blender::gpu { - class MTLTexture : public Texture { friend class MTLContext; friend class MTLStateManager; @@ -242,7 +219,7 @@ class MTLTexture : public Texture { id<MTLBuffer> vert_buffer_mtl_; int vert_buffer_offset_; - /* Core parameters and subresources. */ + /* Core parameters and sub-resources. */ eGPUTextureUsage gpu_image_usage_flags_; /* Whether the texture's properties or state has changed (e.g. mipmap range), and re-baking of diff --git a/source/blender/gpu/metal/mtl_texture.mm b/source/blender/gpu/metal/mtl_texture.mm index df3efdd12e7..ca19d1f9e4b 100644 --- a/source/blender/gpu/metal/mtl_texture.mm +++ b/source/blender/gpu/metal/mtl_texture.mm @@ -563,7 +563,7 @@ void gpu::MTLTexture::update_sub( return; } - /* Check Format writeability. */ + /* Check Format write-ability. */ if (mtl_format_get_writeable_view_format(destination_format) == MTLPixelFormatInvalid) { MTL_LOG_ERROR( "[Error]: Updating texture -- destination MTLPixelFormat '%d' does not support write " @@ -1163,7 +1163,7 @@ void gpu::MTLTexture::mip_range_set(int min, int max) { BLI_assert(min <= max && min >= 0 && max <= mipmaps_); - /* Note: + /* NOTE: * - mip_min_ and mip_max_ are used to Clamp LODs during sampling. * - Given functions like Framebuffer::recursive_downsample modifies the mip range * between each layer, we do not want to be re-baking the texture. @@ -1769,8 +1769,8 @@ void gpu::MTLTexture::ensure_baked() /* CUBE TEXTURES */ case GPU_TEXTURE_CUBE: case GPU_TEXTURE_CUBE_ARRAY: { - /* Note: For a cubemap 'Texture::d_' refers to total number of faces, not just array slices - */ + /* NOTE: For a cube-map 'Texture::d_' refers to total number of faces, + * not just array slices. */ BLI_assert(this->w_ > 0 && this->h_ > 0); this->texture_descriptor_ = [[MTLTextureDescriptor alloc] init]; this->texture_descriptor_.pixelFormat = mtl_format; diff --git a/source/blender/gpu/opengl/gl_texture.hh b/source/blender/gpu/opengl/gl_texture.hh index 2dde8d6c86b..e5b879f1f15 100644 --- a/source/blender/gpu/opengl/gl_texture.hh +++ b/source/blender/gpu/opengl/gl_texture.hh @@ -363,7 +363,7 @@ inline GLenum to_gl_data_format(eGPUTextureFormat format) } /** - * Assume Unorm / Float target. Used with #glReadPixels. + * Assume UNORM/Float target. Used with #glReadPixels. */ inline GLenum channel_len_to_gl(int channel_len) { diff --git a/source/blender/gpu/opengl/gl_vertex_array.cc b/source/blender/gpu/opengl/gl_vertex_array.cc index 04f60f10d41..cfcf77fe705 100644 --- a/source/blender/gpu/opengl/gl_vertex_array.cc +++ b/source/blender/gpu/opengl/gl_vertex_array.cc @@ -39,8 +39,8 @@ static uint16_t vbo_bind(const ShaderInterface *interface, const GPUVertAttr *a = &format->attrs[a_idx]; if (format->deinterleaved) { - offset += ((a_idx == 0) ? 0 : format->attrs[a_idx - 1].sz) * v_len; - stride = a->sz; + offset += ((a_idx == 0) ? 0 : format->attrs[a_idx - 1].size) * v_len; + stride = a->size; } else { offset = a->offset; diff --git a/source/blender/gpu/opengl/gl_vertex_buffer.cc b/source/blender/gpu/opengl/gl_vertex_buffer.cc index a7a0c92431f..6942a220892 100644 --- a/source/blender/gpu/opengl/gl_vertex_buffer.cc +++ b/source/blender/gpu/opengl/gl_vertex_buffer.cc @@ -5,6 +5,8 @@ * \ingroup gpu */ +#include "GPU_texture.h" + #include "gl_context.hh" #include "gl_vertex_buffer.hh" @@ -38,6 +40,7 @@ void GLVertBuf::release_data() } if (vbo_id_ != 0) { + GPU_TEXTURE_FREE_SAFE(buffer_texture_); GLContext::buf_free(vbo_id_); vbo_id_ = 0; memory_usage -= vbo_size_; @@ -51,6 +54,7 @@ void GLVertBuf::duplicate_data(VertBuf *dst_) BLI_assert(GLContext::get() != nullptr); GLVertBuf *src = this; GLVertBuf *dst = static_cast<GLVertBuf *>(dst_); + dst->buffer_texture_ = nullptr; if (src->vbo_id_ != 0) { dst->vbo_size_ = src->size_used_get(); @@ -111,6 +115,16 @@ void GLVertBuf::bind_as_ssbo(uint binding) glBindBufferBase(GL_SHADER_STORAGE_BUFFER, binding, vbo_id_); } +void GLVertBuf::bind_as_texture(uint binding) +{ + bind(); + BLI_assert(vbo_id_ != 0); + if (buffer_texture_ == nullptr) { + buffer_texture_ = GPU_texture_create_from_vertbuf("vertbuf_as_texture", wrap(this)); + } + GPU_texture_bind(buffer_texture_, binding); +} + const void *GLVertBuf::read() const { BLI_assert(is_active()); diff --git a/source/blender/gpu/opengl/gl_vertex_buffer.hh b/source/blender/gpu/opengl/gl_vertex_buffer.hh index 4c29c17dcf7..88d2a455778 100644 --- a/source/blender/gpu/opengl/gl_vertex_buffer.hh +++ b/source/blender/gpu/opengl/gl_vertex_buffer.hh @@ -11,6 +11,8 @@ #include "glew-mx.h" +#include "GPU_texture.h" + #include "gpu_vertex_buffer_private.hh" namespace blender { @@ -23,6 +25,8 @@ class GLVertBuf : public VertBuf { private: /** OpenGL buffer handle. Init on first upload. Immutable after that. */ GLuint vbo_id_ = 0; + /** Texture used if the buffer is bound as buffer texture. Init on first use. */ + struct ::GPUTexture *buffer_texture_ = nullptr; /** Defines whether the buffer handle is wrapped by this GLVertBuf, i.e. we do not own it and * should not free it. */ bool is_wrapper_ = false; @@ -46,6 +50,7 @@ class GLVertBuf : public VertBuf { void upload_data() override; void duplicate_data(VertBuf *dst) override; void bind_as_ssbo(uint binding) override; + void bind_as_texture(uint binding) override; private: bool is_active() const; diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_color_ramp.glsl b/source/blender/gpu/shaders/common/gpu_shader_common_color_ramp.glsl index 17240da4050..17240da4050 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_color_ramp.glsl +++ b/source/blender/gpu/shaders/common/gpu_shader_common_color_ramp.glsl diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_color_util.glsl b/source/blender/gpu/shaders/common/gpu_shader_common_color_utils.glsl index a5c3a990d90..fe89985ae7f 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_color_util.glsl +++ b/source/blender/gpu/shaders/common/gpu_shader_common_color_utils.glsl @@ -90,6 +90,56 @@ void hsv_to_rgb(vec4 hsv, out vec4 outcol) outcol = vec4(rgb, hsv.w); } +void rgb_to_hsl(vec4 rgb, out vec4 outcol) +{ + float cmax, cmin, h, s, l; + + cmax = max(rgb[0], max(rgb[1], rgb[2])); + cmin = min(rgb[0], min(rgb[1], rgb[2])); + l = min(1.0, (cmax + cmin) / 2.0); + + if (cmax == cmin) { + h = s = 0.0; /* achromatic */ + } + else { + float cdelta = cmax - cmin; + s = l > 0.5 ? cdelta / (2.0 - cmax - cmin) : cdelta / (cmax + cmin); + if (cmax == rgb[0]) { + h = (rgb[1] - rgb[2]) / cdelta + (rgb[1] < rgb[2] ? 6.0 : 0.0); + } + else if (cmax == rgb[1]) { + h = (rgb[2] - rgb[0]) / cdelta + 2.0; + } + else { + h = (rgb[0] - rgb[1]) / cdelta + 4.0; + } + } + h /= 6.0; + + outcol = vec4(h, s, l, rgb.w); +} + +void hsl_to_rgb(vec4 hsl, out vec4 outcol) +{ + float nr, ng, nb, chroma, h, s, l; + + h = hsl[0]; + s = hsl[1]; + l = hsl[2]; + + nr = abs(h * 6.0 - 3.0) - 1.0; + ng = 2.0 - abs(h * 6.0 - 2.0); + nb = 2.0 - abs(h * 6.0 - 4.0); + + nr = clamp(nr, 0.0, 1.0); + nb = clamp(nb, 0.0, 1.0); + ng = clamp(ng, 0.0, 1.0); + + chroma = (1.0 - abs(2.0 * l - 1.0)) * s; + + outcol = vec4((nr - 0.5) * chroma + l, (ng - 0.5) * chroma + l, (nb - 0.5) * chroma + l, hsl.w); +} + void color_alpha_clear(vec4 color, out vec4 result) { result = vec4(color.rgb, 1.0); diff --git a/source/blender/gpu/shaders/common/gpu_shader_common_curves.glsl b/source/blender/gpu/shaders/common/gpu_shader_common_curves.glsl new file mode 100644 index 00000000000..8948ed77557 --- /dev/null +++ b/source/blender/gpu/shaders/common/gpu_shader_common_curves.glsl @@ -0,0 +1,162 @@ +vec4 white_balance(vec4 color, vec4 black_level, vec4 white_level) +{ + vec4 range = max(white_level - black_level, vec4(1e-5f)); + return (color - black_level) / range; +} + +float extrapolate_if_needed(float parameter, float value, float start_slope, float end_slope) +{ + if (parameter < 0.0) { + return value + parameter * start_slope; + } + + if (parameter > 1.0) { + return value + (parameter - 1.0) * end_slope; + } + + return value; +} + +/* Same as extrapolate_if_needed but vectorized. */ +vec3 extrapolate_if_needed(vec3 parameters, vec3 values, vec3 start_slopes, vec3 end_slopes) +{ + vec3 end_or_zero_slopes = mix(vec3(0.0), end_slopes, greaterThan(parameters, vec3(1.0))); + vec3 slopes = mix(end_or_zero_slopes, start_slopes, lessThan(parameters, vec3(0.0))); + parameters = parameters - mix(vec3(0.0), vec3(1.0), greaterThan(parameters, vec3(1.0))); + return values + parameters * slopes; +} + +/* Curve maps are stored in sampler objects that are evaluated in the [0, 1] range, so normalize + * parameters accordingly. */ +#define NORMALIZE_PARAMETER(parameter, minimum, range) ((parameter - minimum) * range) + +void curves_combined_rgb(float factor, + vec4 color, + vec4 black_level, + vec4 white_level, + sampler1DArray curve_map, + const float layer, + vec4 range_minimums, + vec4 range_dividers, + vec4 start_slopes, + vec4 end_slopes, + out vec4 result) +{ + vec4 balanced = white_balance(color, black_level, white_level); + + /* First, evaluate alpha curve map at all channels. The alpha curve is the Combined curve in the + * UI. */ + vec3 parameters = NORMALIZE_PARAMETER(balanced.rgb, range_minimums.aaa, range_dividers.aaa); + result.r = texture(curve_map, vec2(parameters.x, layer)).a; + result.g = texture(curve_map, vec2(parameters.y, layer)).a; + result.b = texture(curve_map, vec2(parameters.z, layer)).a; + + /* Then, extrapolate if needed. */ + result.rgb = extrapolate_if_needed(parameters, result.rgb, start_slopes.aaa, end_slopes.aaa); + + /* Then, evaluate each channel on its curve map. */ + parameters = NORMALIZE_PARAMETER(result.rgb, range_minimums.rgb, range_dividers.rgb); + result.r = texture(curve_map, vec2(parameters.r, layer)).r; + result.g = texture(curve_map, vec2(parameters.g, layer)).g; + result.b = texture(curve_map, vec2(parameters.b, layer)).b; + + /* Then, extrapolate again if needed. */ + result.rgb = extrapolate_if_needed(parameters, result.rgb, start_slopes.rgb, end_slopes.rgb); + result.a = color.a; + + result = mix(color, result, factor); +} + +void curves_combined_only(float factor, + vec4 color, + vec4 black_level, + vec4 white_level, + sampler1DArray curve_map, + const float layer, + float range_minimum, + float range_divider, + float start_slope, + float end_slope, + out vec4 result) +{ + vec4 balanced = white_balance(color, black_level, white_level); + + /* Evaluate alpha curve map at all channels. The alpha curve is the Combined curve in the + * UI. */ + vec3 parameters = NORMALIZE_PARAMETER(balanced.rgb, range_minimum, range_divider); + result.r = texture(curve_map, vec2(parameters.x, layer)).a; + result.g = texture(curve_map, vec2(parameters.y, layer)).a; + result.b = texture(curve_map, vec2(parameters.z, layer)).a; + + /* Then, extrapolate if needed. */ + result.rgb = extrapolate_if_needed(parameters, result.rgb, vec3(start_slope), vec3(end_slope)); + result.a = color.a; + + result = mix(color, result, factor); +} + +void curves_vector(vec3 vector, + sampler1DArray curve_map, + const float layer, + vec3 range_minimums, + vec3 range_dividers, + vec3 start_slopes, + vec3 end_slopes, + out vec3 result) +{ + /* Evaluate each component on its curve map. */ + vec3 parameters = NORMALIZE_PARAMETER(vector, range_minimums, range_dividers); + result.x = texture(curve_map, vec2(parameters.x, layer)).x; + result.y = texture(curve_map, vec2(parameters.y, layer)).y; + result.z = texture(curve_map, vec2(parameters.z, layer)).z; + + /* Then, extrapolate if needed. */ + result = extrapolate_if_needed(parameters, result, start_slopes, end_slopes); +} + +void curves_vector_mixed(float factor, + vec3 vector, + sampler1DArray curve_map, + const float layer, + vec3 range_minimums, + vec3 range_dividers, + vec3 start_slopes, + vec3 end_slopes, + out vec3 result) +{ + curves_vector( + vector, curve_map, layer, range_minimums, range_dividers, start_slopes, end_slopes, result); + result = mix(vector, result, factor); +} + +void curves_float(float value, + sampler1DArray curve_map, + const float layer, + float range_minimum, + float range_divider, + float start_slope, + float end_slope, + out float result) +{ + /* Evaluate the normalized value on the first curve map. */ + float parameter = NORMALIZE_PARAMETER(value, range_minimum, range_divider); + result = texture(curve_map, vec2(parameter, layer)).x; + + /* Then, extrapolate if needed. */ + result = extrapolate_if_needed(parameter, result, start_slope, end_slope); +} + +void curves_float_mixed(float factor, + float value, + sampler1DArray curve_map, + const float layer, + float range_minimum, + float range_divider, + float start_slope, + float end_slope, + out float result) +{ + curves_float( + value, curve_map, layer, range_minimum, range_divider, start_slope, end_slope, result); + result = mix(value, result, factor); +} diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hash.glsl b/source/blender/gpu/shaders/common/gpu_shader_common_hash.glsl index 32d61f06a65..32d61f06a65 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_hash.glsl +++ b/source/blender/gpu/shaders/common/gpu_shader_common_hash.glsl diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl b/source/blender/gpu/shaders/common/gpu_shader_common_math.glsl index 0948ce2c9fa..5f640f64056 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl +++ b/source/blender/gpu/shaders/common/gpu_shader_common_math.glsl @@ -1,4 +1,4 @@ -#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl) void math_add(float a, float b, float c, out float result) { diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl b/source/blender/gpu/shaders/common/gpu_shader_common_math_utils.glsl index 91a8996939a..124654963fd 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl +++ b/source/blender/gpu/shaders/common/gpu_shader_common_math_utils.glsl @@ -139,75 +139,3 @@ mat3 euler_to_mat3(vec3 euler) mat[2][2] = cy * cx; return mat; } - -void normal_transform_object_to_world(vec3 vin, out vec3 vout) -{ - vout = normal_object_to_world(vin); -} - -void normal_transform_world_to_object(vec3 vin, out vec3 vout) -{ - vout = normal_world_to_object(vin); -} - -void direction_transform_object_to_world(vec3 vin, out vec3 vout) -{ - vout = transform_direction(ModelMatrix, vin); -} - -void direction_transform_object_to_view(vec3 vin, out vec3 vout) -{ - vout = transform_direction(ModelMatrix, vin); - vout = transform_direction(ViewMatrix, vout); -} - -void direction_transform_view_to_world(vec3 vin, out vec3 vout) -{ - vout = transform_direction(ViewMatrixInverse, vin); -} - -void direction_transform_view_to_object(vec3 vin, out vec3 vout) -{ - vout = transform_direction(ViewMatrixInverse, vin); - vout = transform_direction(ModelMatrixInverse, vout); -} - -void direction_transform_world_to_view(vec3 vin, out vec3 vout) -{ - vout = transform_direction(ViewMatrix, vin); -} - -void direction_transform_world_to_object(vec3 vin, out vec3 vout) -{ - vout = transform_direction(ModelMatrixInverse, vin); -} - -void point_transform_object_to_world(vec3 vin, out vec3 vout) -{ - vout = point_object_to_world(vin); -} - -void point_transform_object_to_view(vec3 vin, out vec3 vout) -{ - vout = point_object_to_view(vin); -} - -void point_transform_view_to_world(vec3 vin, out vec3 vout) -{ - vout = point_view_to_world(vin); -} - -void point_transform_view_to_object(vec3 vin, out vec3 vout) -{ - vout = point_view_to_object(vin); -} - -void point_transform_world_to_view(vec3 vin, out vec3 vout) -{ - vout = point_world_to_view(vin); -} - -void point_transform_world_to_object(vec3 vin, out vec3 vout) -{ - vout = point_world_to_object(vin); -} diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl b/source/blender/gpu/shaders/common/gpu_shader_common_mix_rgb.glsl index 157a6a27c15..f9652f1150b 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl +++ b/source/blender/gpu/shaders/common/gpu_shader_common_mix_rgb.glsl @@ -1,4 +1,4 @@ -#pragma BLENDER_REQUIRE(gpu_shader_material_color_util.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl) void mix_blend(float fac, vec4 col1, vec4 col2, out vec4 outcol) { diff --git a/source/blender/gpu/shaders/gpu_shader_geometry.glsl b/source/blender/gpu/shaders/gpu_shader_geometry.glsl deleted file mode 100644 index e0e899cfb35..00000000000 --- a/source/blender/gpu/shaders/gpu_shader_geometry.glsl +++ /dev/null @@ -1,93 +0,0 @@ - -#define INTERP_FACE_VARYING_2(result, fvarOffset, tessCoord) \ - { \ - vec2 v[4]; \ - int primOffset = (gl_PrimitiveID + PrimitiveIdBase) * 4; \ - for (int i = 0; i < 4; i++) { \ - int index = (primOffset + i) * osd_fvar_count + fvarOffset; \ - v[i] = vec2(texelFetch(FVarDataBuffer, index).s, texelFetch(FVarDataBuffer, index + 1).s); \ - } \ - result = mix(mix(v[0], v[1], tessCoord.s), mix(v[3], v[2], tessCoord.s), tessCoord.t); \ - } - -#define INTERP_FACE_VARYING_ATT_2(result, fvarOffset, tessCoord) \ - { \ - vec2 tmp; \ - INTERP_FACE_VARYING_2(tmp, fvarOffset, tessCoord); \ - result = vec3(tmp, 0); \ - } - -out block -{ - VertexData v; -} -outpt; - -void set_mtface_vertex_attrs(vec2 st); - -void emit_flat(int index, vec3 normal) -{ - outpt.v.position = inpt[index].v.position; - outpt.v.normal = normal; - - /* Compatibility */ - varnormal = outpt.v.normal; - varposition = outpt.v.position.xyz; - - /* TODO(sergey): Only uniform subdivisions atm. */ - vec2 quadst[4] = vec2[](vec2(0, 0), vec2(1, 0), vec2(1, 1), vec2(0, 1)); - vec2 st = quadst[index]; - - INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st); - - set_mtface_vertex_attrs(st); - - gl_Position = ProjectionMatrix * inpt[index].v.position; - EmitVertex(); -} - -void emit_smooth(int index) -{ - outpt.v.position = inpt[index].v.position; - outpt.v.normal = inpt[index].v.normal; - - /* Compatibility */ - varnormal = outpt.v.normal; - varposition = outpt.v.position.xyz; - - /* TODO(sergey): Only uniform subdivisions atm. */ - vec2 quadst[4] = vec2[](vec2(0, 0), vec2(1, 0), vec2(1, 1), vec2(0, 1)); - vec2 st = quadst[index]; - - INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st); - - set_mtface_vertex_attrs(st); - - gl_Position = ProjectionMatrix * inpt[index].v.position; - EmitVertex(); -} - -void main() -{ - gl_PrimitiveID = gl_PrimitiveIDIn; - - if (osd_flat_shading) { - vec3 A = (inpt[0].v.position - inpt[1].v.position).xyz; - vec3 B = (inpt[3].v.position - inpt[1].v.position).xyz; - vec3 flat_normal = normalize(cross(B, A)); - emit_flat(0, flat_normal); - emit_flat(1, flat_normal); - emit_flat(3, flat_normal); - emit_flat(2, flat_normal); - } - else { - emit_smooth(0); - emit_smooth(1); - emit_smooth(3); - emit_smooth(2); - } - EndPrimitive(); -} - -void set_mtface_vertex_attrs(vec2 st) -{ diff --git a/source/blender/gpu/shaders/infos/gpu_shader_3D_image_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_3D_image_info.hh new file mode 100644 index 00000000000..94cf58933af --- /dev/null +++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_image_info.hh @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "gpu_interface_info.hh" +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(gpu_shader_3D_image) + .vertex_in(0, Type::VEC3, "pos") + .vertex_in(1, Type::VEC2, "texCoord") + .vertex_out(smooth_tex_coord_interp_iface) + .fragment_out(0, Type::VEC4, "fragColor") + .push_constant(Type::MAT4, "ModelViewProjectionMatrix") + .sampler(0, ImageType::FLOAT_2D, "image") + .vertex_source("gpu_shader_3D_image_vert.glsl") + .fragment_source("gpu_shader_image_frag.glsl") + .do_static_compilation(true); diff --git a/source/blender/gpu/shaders/infos/gpu_shader_3D_uniform_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_3D_uniform_color_info.hh index 369fe3ac293..ae7edeb16e2 100644 --- a/source/blender/gpu/shaders/infos/gpu_shader_3D_uniform_color_info.hh +++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_uniform_color_info.hh @@ -28,7 +28,7 @@ GPU_SHADER_CREATE_INFO(gpu_shader_3D_clipped_uniform_color) .fragment_out(0, Type::VEC4, "fragColor") .push_constant(Type::MAT4, "ModelViewProjectionMatrix") .push_constant(Type::VEC4, "color") - /* TODO(fclem): Put thoses two to one UBO. */ + /* TODO(@fclem): Put those two to one UBO. */ .push_constant(Type::MAT4, "ModelMatrix") .push_constant(Type::VEC4, "ClipPlane") .vertex_source("gpu_shader_3D_clipped_uniform_color_vert.glsl") diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_combine_color.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_combine_color.glsl new file mode 100644 index 00000000000..e68d0d98484 --- /dev/null +++ b/source/blender/gpu/shaders/material/gpu_shader_material_combine_color.glsl @@ -0,0 +1,16 @@ +#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl) + +void combine_color_rgb(float r, float g, float b, out vec4 col) +{ + col = vec4(r, g, b, 1.0); +} + +void combine_color_hsv(float h, float s, float v, out vec4 col) +{ + hsv_to_rgb(vec4(h, s, v, 1.0), col); +} + +void combine_color_hsl(float h, float s, float l, out vec4 col) +{ + hsl_to_rgb(vec4(h, s, l, 1.0), col); +} diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl index e8f444080b9..4d9e16afe66 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl @@ -1,4 +1,4 @@ -#pragma BLENDER_REQUIRE(gpu_shader_material_color_util.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl) void combine_hsv(float h, float s, float v, out vec4 col) { diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_float_curve.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_float_curve.glsl deleted file mode 100644 index 514409f7fdf..00000000000 --- a/source/blender/gpu/shaders/material/gpu_shader_material_float_curve.glsl +++ /dev/null @@ -1,33 +0,0 @@ -/* ext is vec4(in_x, in_dy, out_x, out_dy). */ -float curve_float_extrapolate(float x, float y, vec4 ext) -{ - if (x < 0.0) { - return y + x * ext.y; - } - else if (x > 1.0) { - return y + (x - 1.0) * ext.w; - } - else { - return y; - } -} - -#define RANGE_RESCALE(x, min, range) ((x - min) * range) - -void curve_float(float fac, - float vec, - sampler1DArray curvemap, - float layer, - float range, - vec4 ext, - out float outvec) -{ - float xyz_min = ext.x; - vec = RANGE_RESCALE(vec, xyz_min, range); - - outvec = texture(curvemap, vec2(vec, layer)).x; - - outvec = curve_float_extrapolate(vec, outvec, ext); - - outvec = mix(vec, outvec, fac); -} diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl index 7f502f74c0c..6d52e97cca1 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl @@ -1,4 +1,4 @@ -#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_hash.glsl) #pragma BLENDER_REQUIRE(gpu_shader_material_noise.glsl) /* The fractal_noise functions are all exactly the same except for the input type. */ diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl index 29fb09ceebd..64681cd795a 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl @@ -1,4 +1,4 @@ -#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl) void node_gamma(vec4 col, float gamma, out vec4 outcol) { diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl index 2d5114c3bad..61458b05c86 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl @@ -1,4 +1,4 @@ -#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_hash.glsl) void node_hair_info(float hair_length, out float is_strand, diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl index 30b808508e9..5223828e176 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl @@ -1,4 +1,4 @@ -#pragma BLENDER_REQUIRE(gpu_shader_material_color_util.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl) void hue_sat(float hue, float sat, float value, float fac, vec4 col, out vec4 outcol) { diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl index 119ee3c0eaa..a81e6d36a55 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl @@ -1,4 +1,4 @@ -#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl) float smootherstep(float edge0, float edge1, float x) { diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl index 312c57231c5..b59257506c9 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl @@ -1,4 +1,4 @@ -#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl) void mapping_mat4( vec3 vec, vec4 m0, vec4 m1, vec4 m2, vec4 m3, vec3 minvec, vec3 maxvec, out vec3 outvec) diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl index c84f34a834c..881e38ea11a 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl @@ -1,4 +1,4 @@ -#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_hash.glsl) /* clang-format off */ #define FLOORFRAC(x, x_int, x_fract) { float x_floor = floor(x); x_int = int(x_floor); x_fract = x - x_floor; } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl index ad3d4737193..251103ae57c 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl @@ -1,4 +1,4 @@ -#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_hash.glsl) void node_point_info(out vec3 position, out float radius, out float random) { diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_rgb_curves.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_rgb_curves.glsl deleted file mode 100644 index 054fdddf7c3..00000000000 --- a/source/blender/gpu/shaders/material/gpu_shader_material_rgb_curves.glsl +++ /dev/null @@ -1,73 +0,0 @@ -/* ext is vec4(in_x, in_dy, out_x, out_dy). */ -float curve_extrapolate(float x, float y, vec4 ext) -{ - if (x < 0.0) { - return y + x * ext.y; - } - else if (x > 1.0) { - return y + (x - 1.0) * ext.w; - } - else { - return y; - } -} - -#define RANGE_RESCALE(x, min, range) ((x - min) * range) - -void curves_rgb(float fac, - vec4 col, - sampler1DArray curvemap, - float layer, - vec4 range, - vec4 ext_r, - vec4 ext_g, - vec4 ext_b, - vec4 ext_a, - out vec4 outcol) -{ - vec4 co = vec4(RANGE_RESCALE(col.rgb, ext_a.x, range.a), layer); - vec3 samp; - samp.r = texture(curvemap, co.xw).a; - samp.g = texture(curvemap, co.yw).a; - samp.b = texture(curvemap, co.zw).a; - - samp.r = curve_extrapolate(co.x, samp.r, ext_a); - samp.g = curve_extrapolate(co.y, samp.g, ext_a); - samp.b = curve_extrapolate(co.z, samp.b, ext_a); - - vec3 rgb_min = vec3(ext_r.x, ext_g.x, ext_b.x); - co.xyz = RANGE_RESCALE(samp.rgb, rgb_min, range.rgb); - - samp.r = texture(curvemap, co.xw).r; - samp.g = texture(curvemap, co.yw).g; - samp.b = texture(curvemap, co.zw).b; - - outcol.r = curve_extrapolate(co.x, samp.r, ext_r); - outcol.g = curve_extrapolate(co.y, samp.g, ext_g); - outcol.b = curve_extrapolate(co.z, samp.b, ext_b); - outcol.a = col.a; - - outcol = mix(col, outcol, fac); -} - -void curves_rgb_opti(float fac, - vec4 col, - sampler1DArray curvemap, - float layer, - vec4 range, - vec4 ext_a, - out vec4 outcol) -{ - vec4 co = vec4(RANGE_RESCALE(col.rgb, ext_a.x, range.a), layer); - vec3 samp; - samp.r = texture(curvemap, co.xw).a; - samp.g = texture(curvemap, co.yw).a; - samp.b = texture(curvemap, co.zw).a; - - outcol.r = curve_extrapolate(co.x, samp.r, ext_a); - outcol.g = curve_extrapolate(co.y, samp.g, ext_a); - outcol.b = curve_extrapolate(co.z, samp.b, ext_a); - outcol.a = col.a; - - outcol = mix(col, outcol, fac); -} diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_separate_color.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_separate_color.glsl new file mode 100644 index 00000000000..2dd51029cef --- /dev/null +++ b/source/blender/gpu/shaders/material/gpu_shader_material_separate_color.glsl @@ -0,0 +1,28 @@ +#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl) + +void separate_color_rgb(vec4 col, out float r, out float g, out float b) +{ + r = col.r; + g = col.g; + b = col.b; +} + +void separate_color_hsv(vec4 col, out float r, out float g, out float b) +{ + vec4 hsv; + + rgb_to_hsv(col, hsv); + r = hsv[0]; + g = hsv[1]; + b = hsv[2]; +} + +void separate_color_hsl(vec4 col, out float r, out float g, out float b) +{ + vec4 hsl; + + rgb_to_hsl(col, hsl); + r = hsl[0]; + g = hsl[1]; + b = hsl[2]; +} diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl index 180e0fd1940..8e475ec39a7 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl @@ -1,4 +1,4 @@ -#pragma BLENDER_REQUIRE(gpu_shader_material_color_util.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl) void separate_hsv(vec4 col, out float h, out float s, out float v) { diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl index edc2fa32177..8d9773913ff 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl @@ -1,5 +1,5 @@ -#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl) -#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_hash.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl) vec2 calc_brick_texture(vec3 p, float mortar_size, diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl index da131978f72..cf7d6ae18e6 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl @@ -1,4 +1,4 @@ -#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl) void node_tex_environment_equirectangular(vec3 co, out vec3 uv) { diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl index 1552a2facc3..961fe23e67e 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl @@ -1,4 +1,4 @@ -#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_hash.glsl) #pragma BLENDER_REQUIRE(gpu_shader_material_noise.glsl) /* 1D Musgrave fBm diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl index c90b2211dcf..3df6f7b29fb 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl @@ -1,4 +1,4 @@ -#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_hash.glsl) #pragma BLENDER_REQUIRE(gpu_shader_material_noise.glsl) #pragma BLENDER_REQUIRE(gpu_shader_material_fractal_noise.glsl) diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl index dd12b602edf..0fb8ef15f5f 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl @@ -1,5 +1,5 @@ -#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl) -#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_hash.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl) /* * Original code is under the MIT License, Copyright (c) 2013 Inigo Quilez. diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl index eed98232d0b..c24a9417219 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl @@ -1,4 +1,4 @@ -#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_hash.glsl) #pragma BLENDER_REQUIRE(gpu_shader_material_noise.glsl) #pragma BLENDER_REQUIRE(gpu_shader_material_fractal_noise.glsl) diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl index 030b58f0736..c5081372aa4 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl @@ -1,4 +1,4 @@ -#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_hash.glsl) /* White Noise */ diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_transform_utils.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_transform_utils.glsl new file mode 100644 index 00000000000..87048e5c5d6 --- /dev/null +++ b/source/blender/gpu/shaders/material/gpu_shader_material_transform_utils.glsl @@ -0,0 +1,71 @@ +void normal_transform_object_to_world(vec3 vin, out vec3 vout) +{ + vout = normal_object_to_world(vin); +} + +void normal_transform_world_to_object(vec3 vin, out vec3 vout) +{ + vout = normal_world_to_object(vin); +} + +void direction_transform_object_to_world(vec3 vin, out vec3 vout) +{ + vout = transform_direction(ModelMatrix, vin); +} + +void direction_transform_object_to_view(vec3 vin, out vec3 vout) +{ + vout = transform_direction(ModelMatrix, vin); + vout = transform_direction(ViewMatrix, vout); +} + +void direction_transform_view_to_world(vec3 vin, out vec3 vout) +{ + vout = transform_direction(ViewMatrixInverse, vin); +} + +void direction_transform_view_to_object(vec3 vin, out vec3 vout) +{ + vout = transform_direction(ViewMatrixInverse, vin); + vout = transform_direction(ModelMatrixInverse, vout); +} + +void direction_transform_world_to_view(vec3 vin, out vec3 vout) +{ + vout = transform_direction(ViewMatrix, vin); +} + +void direction_transform_world_to_object(vec3 vin, out vec3 vout) +{ + vout = transform_direction(ModelMatrixInverse, vin); +} + +void point_transform_object_to_world(vec3 vin, out vec3 vout) +{ + vout = point_object_to_world(vin); +} + +void point_transform_object_to_view(vec3 vin, out vec3 vout) +{ + vout = point_object_to_view(vin); +} + +void point_transform_view_to_world(vec3 vin, out vec3 vout) +{ + vout = point_view_to_world(vin); +} + +void point_transform_view_to_object(vec3 vin, out vec3 vout) +{ + vout = point_view_to_object(vin); +} + +void point_transform_world_to_view(vec3 vin, out vec3 vout) +{ + vout = point_world_to_view(vin); +} + +void point_transform_world_to_object(vec3 vin, out vec3 vout) +{ + vout = point_world_to_object(vin); +} diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vector_curves.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vector_curves.glsl deleted file mode 100644 index f6dec1b24e2..00000000000 --- a/source/blender/gpu/shaders/material/gpu_shader_material_vector_curves.glsl +++ /dev/null @@ -1,41 +0,0 @@ -/* ext is vec4(in_x, in_dy, out_x, out_dy). */ -float curve_vec_extrapolate(float x, float y, vec4 ext) -{ - if (x < 0.0) { - return y + x * ext.y; - } - else if (x > 1.0) { - return y + (x - 1.0) * ext.w; - } - else { - return y; - } -} - -#define RANGE_RESCALE(x, min, range) ((x - min) * range) - -void curves_vec(float fac, - vec3 vec, - sampler1DArray curvemap, - float layer, - vec3 range, - vec4 ext_x, - vec4 ext_y, - vec4 ext_z, - out vec3 outvec) -{ - vec4 co = vec4(vec, layer); - - vec3 xyz_min = vec3(ext_x.x, ext_y.x, ext_z.x); - co.xyz = RANGE_RESCALE(co.xyz, xyz_min, range); - - outvec.x = texture(curvemap, co.xw).x; - outvec.y = texture(curvemap, co.yw).y; - outvec.z = texture(curvemap, co.zw).z; - - outvec.x = curve_vec_extrapolate(co.x, outvec.r, ext_x); - outvec.y = curve_vec_extrapolate(co.y, outvec.g, ext_y); - outvec.z = curve_vec_extrapolate(co.z, outvec.b, ext_z); - - outvec = mix(vec, outvec, fac); -} diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl index 8f6bf17f195..018784c42a5 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl @@ -1,4 +1,4 @@ -#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl) void vector_math_add(vec3 a, vec3 b, vec3 c, float scale, out vec3 outVector, out float outValue) { diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vector_rotate.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vector_rotate.glsl index ff0fb1c0418..8f7bd26ca18 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_vector_rotate.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_vector_rotate.glsl @@ -1,4 +1,4 @@ -#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl) vec3 rotate_around_axis(vec3 p, vec3 axis, float angle) { diff --git a/source/blender/gpu/tests/gpu_shader_builtin_test.cc b/source/blender/gpu/tests/gpu_shader_builtin_test.cc index 6ef8a032a73..5dc70a8bf0f 100644 --- a/source/blender/gpu/tests/gpu_shader_builtin_test.cc +++ b/source/blender/gpu/tests/gpu_shader_builtin_test.cc @@ -35,6 +35,7 @@ static void test_shader_builtin() test_compile_builtin_shader(GPU_SHADER_2D_UNIFORM_COLOR, GPU_SHADER_CFG_DEFAULT); test_compile_builtin_shader(GPU_SHADER_2D_FLAT_COLOR, GPU_SHADER_CFG_DEFAULT); test_compile_builtin_shader(GPU_SHADER_2D_SMOOTH_COLOR, GPU_SHADER_CFG_DEFAULT); + test_compile_builtin_shader(GPU_SHADER_3D_IMAGE, GPU_SHADER_CFG_DEFAULT); test_compile_builtin_shader(GPU_SHADER_2D_IMAGE, GPU_SHADER_CFG_DEFAULT); test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_COLOR, GPU_SHADER_CFG_DEFAULT); test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_DESATURATE_COLOR, GPU_SHADER_CFG_DEFAULT); |