GPU: Refactor texture samplers #105642

Merged
Omar Emara merged 9 commits from OmarEmaraDev/blender:texture-sampler-refactor into main 2023-04-04 15:16:20 +02:00
68 changed files with 1017 additions and 418 deletions

View File

@ -230,7 +230,7 @@ class DisplayGPUTexture {
}
GPU_texture_filter_mode(gpu_texture, false);
GPU_texture_wrap_mode(gpu_texture, false, true);
GPU_texture_extend_mode(gpu_texture, GPU_SAMPLER_EXTEND_MODE_EXTEND);
++num_used;
@ -705,14 +705,14 @@ static void draw_tile(const float2 &zoom,
const float zoomed_height = draw_tile.params.size.y * zoom.y;
if (texture.width != draw_tile.params.size.x || texture.height != draw_tile.params.size.y) {
/* Resolution divider is different from 1, force nearest interpolation. */
GPU_texture_bind_ex(texture.gpu_texture, GPU_SAMPLER_DEFAULT, 0);
GPU_texture_bind_ex(texture.gpu_texture, GPUSamplerState::default_sampler(), 0);
}
else if (zoomed_width - draw_tile.params.size.x > 0.5f ||
zoomed_height - draw_tile.params.size.y > 0.5f) {
GPU_texture_bind_ex(texture.gpu_texture, GPU_SAMPLER_DEFAULT, 0);
GPU_texture_bind_ex(texture.gpu_texture, GPUSamplerState::default_sampler(), 0);
}
else {
GPU_texture_bind_ex(texture.gpu_texture, GPU_SAMPLER_FILTER, 0);
GPU_texture_bind_ex(texture.gpu_texture, {GPU_SAMPLER_FILTERING_LINEAR}, 0);
}
/* Draw at the parameters for which the texture has been updated for. This allows to always draw

View File

@ -349,7 +349,7 @@ static bool addGPULut1D2D(OCIO_GPUTextures &textures,
}
GPU_texture_filter_mode(lut.texture, interpolation != INTERP_NEAREST);
GPU_texture_wrap_mode(lut.texture, false, true);
GPU_texture_extend_mode(lut.texture, GPU_SAMPLER_EXTEND_MODE_EXTEND);
lut.sampler_name = sampler_name;
@ -387,7 +387,7 @@ static bool addGPULut3D(OCIO_GPUTextures &textures,
}
GPU_texture_filter_mode(lut.texture, interpolation != INTERP_NEAREST);
GPU_texture_wrap_mode(lut.texture, false, true);
GPU_texture_extend_mode(lut.texture, GPU_SAMPLER_EXTEND_MODE_EXTEND);
lut.sampler_name = sampler_name;
@ -453,7 +453,7 @@ static bool createGPUCurveMapping(OCIO_GPUCurveMappping &curvemap,
curvemap.texture = GPU_texture_create_1d(
"OCIOCurveMap", lut_size, 1, GPU_RGBA16F, GPU_TEXTURE_USAGE_SHADER_READ, nullptr);
GPU_texture_filter_mode(curvemap.texture, false);
GPU_texture_wrap_mode(curvemap.texture, false, true);
fclem marked this conversation as resolved Outdated

It seems you did not took into account the clamp to border color case in all of these.

It seems you did not took into account the clamp to border color case in all of these.

Can you clarify this? Where is the clamp to border case here?

Can you clarify this? Where is the clamp to border case here?

Disregard that. I did check all usage and they look right.

Disregard that. I did check all usage and they look right.
GPU_texture_extend_mode(curvemap.texture, GPU_SAMPLER_EXTEND_MODE_EXTEND);
curvemap.buffer = GPU_uniformbuf_create(sizeof(OCIO_GPUCurveMappingParameters));

View File

@ -437,7 +437,7 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
ima->id.name + 2, ibuf_intern, use_high_bitdepth, store_premultiplied);
if (*tex) {
GPU_texture_wrap_mode(*tex, true, false);
GPU_texture_extend_mode(*tex, GPU_SAMPLER_EXTEND_MODE_REPEAT);
if (GPU_mipmap_enabled()) {
GPU_texture_update_mipmap_chain(*tex);

View File

@ -487,7 +487,7 @@ static void studiolight_create_equirect_radiance_gputexture(StudioLight *sl)
ibuf->rect_float);
GPUTexture *tex = sl->equirect_radiance_gputexture;
GPU_texture_filter_mode(tex, true);
GPU_texture_wrap_mode(tex, true, true);
GPU_texture_extend_mode(tex, GPU_SAMPLER_EXTEND_MODE_REPEAT);
}
sl->flag |= STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE;
}
@ -548,7 +548,7 @@ static void studiolight_create_equirect_irradiance_gputexture(StudioLight *sl)
ibuf->rect_float);
GPUTexture *tex = sl->equirect_irradiance_gputexture;
GPU_texture_filter_mode(tex, true);
GPU_texture_wrap_mode(tex, true, true);
GPU_texture_extend_mode(tex, GPU_SAMPLER_EXTEND_MODE_REPEAT);
}
sl->flag |= STUDIOLIGHT_EQUIRECT_IRRADIANCE_GPUTEXTURE;
}

View File

@ -58,11 +58,16 @@ void RealizeOnDomainOperation::execute()
Interpolation::Bicubic);
GPU_texture_filter_mode(input.texture(), use_bilinear);
/* Make out-of-bound texture access return zero by clamping to border color. And make texture
* wrap appropriately if the input repeats. */
const bool repeats = input.get_realization_options().repeat_x ||
input.get_realization_options().repeat_y;
GPU_texture_wrap_mode(input.texture(), repeats, false);
/* If the input repeats, set a repeating wrap mode for out-of-bound texture access. Otherwise,
* make out-of-bound texture access return zero by setting a clamp to border extend mode. */
GPU_texture_extend_mode_x(input.texture(),
input.get_realization_options().repeat_x ?
GPU_SAMPLER_EXTEND_MODE_REPEAT :
GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER);
GPU_texture_extend_mode_y(input.texture(),
input.get_realization_options().repeat_y ?
GPU_SAMPLER_EXTEND_MODE_REPEAT :
GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER);
input.bind_as_texture(shader, "input_tx");
result.bind_as_image(shader, "domain_img");

View File

@ -329,8 +329,10 @@ int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata),
return 0;
}
#define WITH_FILTERING (GPU_SAMPLER_MIPMAP | GPU_SAMPLER_FILTER)
#define NO_FILTERING GPU_SAMPLER_MIPMAP
const static GPUSamplerState WITH_FILTERING = {GPU_SAMPLER_FILTERING_MIPMAP |
GPU_SAMPLER_FILTERING_LINEAR};
const static GPUSamplerState NO_FILTERING = {GPU_SAMPLER_FILTERING_MIPMAP};
#define COLOR_FORMAT fx->dof_color_format
#define FG_TILE_FORMAT GPU_RGBA16F
#define BG_TILE_FORMAT GPU_R11F_G11F_B10F

View File

@ -245,7 +245,8 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
DRW_PASS_CREATE(psl->color_downsample_ps, DRW_STATE_WRITE_COLOR);
grp = DRW_shgroup_create(EEVEE_shaders_effect_downsample_sh_get(), psl->color_downsample_ps);
DRW_shgroup_uniform_texture_ex(grp, "source", txl->filtered_radiance, GPU_SAMPLER_FILTER);
const GPUSamplerState sampler_state = {GPU_SAMPLER_FILTERING_LINEAR};
DRW_shgroup_uniform_texture_ex(grp, "source", txl->filtered_radiance, sampler_state);
DRW_shgroup_uniform_vec2(grp, "texelSize", e_data.texel_size, 1);
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}

View File

@ -227,7 +227,9 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata,
if (probe_render) {
/* Avoid artifact with equirectangular mapping. */
eGPUSamplerState state = (GPU_SAMPLER_FILTER | GPU_SAMPLER_REPEAT_S);
GPUSamplerState state = {GPU_SAMPLER_FILTERING_LINEAR,
GPU_SAMPLER_EXTEND_MODE_REPEAT,
GPU_SAMPLER_EXTEND_MODE_EXTEND};
DRW_shgroup_uniform_float_copy(grp, "studioLightIntensity", shading->studiolight_intensity);
BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE);
DRW_shgroup_uniform_texture_ex(grp, "studioLight", sl->equirect_radiance_gputexture, state);

View File

@ -162,7 +162,7 @@ void EEVEE_motion_blur_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat
}
{
DRW_PASS_CREATE(psl->motion_blur, DRW_STATE_WRITE_COLOR);
eGPUSamplerState state = 0;
const GPUSamplerState state = GPU_SAMPLER_DEFAULT;
int expand_steps = 1 + (max_ii(0, effects->motion_blur_max - 1) / EEVEE_VELOCITY_TILE_SIZE);
GPUTexture *tile_tx = (expand_steps & 1) ? effects->velocity_tiles_x_tx :
effects->velocity_tiles_tx;

View File

@ -150,7 +150,7 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
grp, "randomScale", effects->reflection_trace_full ? 0.0f : 0.5f);
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
eGPUSamplerState no_filter = GPU_SAMPLER_DEFAULT;
GPUSamplerState no_filter = GPU_SAMPLER_DEFAULT;
if (effects->use_split_ssr_pass) {
/* Prepare passes for split reflections resolve variant. */

View File

@ -191,7 +191,7 @@ void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata,
DRW_shgroup_stencil_mask(shgrp, sss_id);
{
eGPUSamplerState state = GPU_SAMPLER_DEFAULT;
GPUSamplerState state = GPU_SAMPLER_DEFAULT;
DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_subsurface_first_pass_sh_get(),
psl->sss_blur_ps);

View File

@ -446,7 +446,7 @@ void DepthOfField::hole_fill_pass_sync()
void DepthOfField::resolve_pass_sync()
{
eGPUSamplerState with_filter = GPU_SAMPLER_FILTER;
GPUSamplerState with_filter = {GPU_SAMPLER_FILTERING_LINEAR};
RenderBuffers &render_buffers = inst_.render_buffers;
eShaderType sh_type = use_bokeh_lut_ ? DOF_RESOLVE_LUT : DOF_RESOLVE;

View File

@ -45,8 +45,9 @@ class DepthOfField {
class Instance &inst_;
/** Samplers */
static constexpr eGPUSamplerState gather_bilinear = GPU_SAMPLER_MIPMAP | GPU_SAMPLER_FILTER;
static constexpr eGPUSamplerState gather_nearest = GPU_SAMPLER_MIPMAP;
static constexpr GPUSamplerState gather_bilinear = {GPU_SAMPLER_FILTERING_MIPMAP |
GPU_SAMPLER_FILTERING_LINEAR};
static constexpr GPUSamplerState gather_nearest = {GPU_SAMPLER_FILTERING_MIPMAP};
/** Input/Output texture references. */
GPUTexture *input_color_tx_ = nullptr;

View File

@ -416,7 +416,7 @@ void Film::sync()
RenderBuffers &rbuffers = inst_.render_buffers;
VelocityModule &velocity = inst_.velocity;
eGPUSamplerState filter = GPU_SAMPLER_FILTER;
GPUSamplerState filter = {GPU_SAMPLER_FILTERING_LINEAR};
/* For viewport, only previous motion is supported.
* Still bind previous step to avoid undefined behavior. */

View File

@ -132,7 +132,7 @@ void MotionBlurModule::sync()
return;
}
eGPUSamplerState no_filter = GPU_SAMPLER_DEFAULT;
GPUSamplerState no_filter = GPUSamplerState::default_sampler();
RenderBuffers &render_buffers = inst_.render_buffers;
motion_blur_ps_.init();

View File

@ -26,8 +26,8 @@ class ShadowPunctual;
using namespace draw;
constexpr eGPUSamplerState no_filter = GPU_SAMPLER_DEFAULT;
constexpr eGPUSamplerState with_filter = GPU_SAMPLER_FILTER;
constexpr GPUSamplerState no_filter = GPUSamplerState::default_sampler();
constexpr GPUSamplerState with_filter = {GPU_SAMPLER_FILTERING_LINEAR};
#endif

View File

@ -198,7 +198,8 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD
for (const TextureInfo &info : instance_data->texture_infos) {
DRWShadingGroup *shgrp_sub = DRW_shgroup_create_sub(shgrp);
DRW_shgroup_uniform_ivec2_copy(shgrp_sub, "offset", info.offset());
DRW_shgroup_uniform_texture_ex(shgrp_sub, "imageTexture", info.texture, GPU_SAMPLER_DEFAULT);
DRW_shgroup_uniform_texture_ex(
shgrp_sub, "imageTexture", info.texture, GPUSamplerState::default_sampler());
DRW_shgroup_call_obmat(shgrp_sub, info.batch, image_mat);
}
}

View File

@ -77,7 +77,8 @@ GPU_SHADER_CREATE_INFO(workbench_next_resolve_curvature)
GPU_SHADER_CREATE_INFO(workbench_next_resolve_cavity)
.define("WORKBENCH_CAVITY")
/* TODO(@pragma37): GPU_SAMPLER_REPEAT is set in CavityEffect, it doesn't work here? */
/* TODO(@pragma37): GPU_SAMPLER_EXTEND_MODE_REPEAT is set in CavityEffect, it doesn't work
here? */
.sampler(8, ImageType::FLOAT_2D, "jitter_tx")
.uniform_buf(5, "vec4", "cavity_samples[512]");

View File

@ -79,7 +79,11 @@ void CavityEffect::setup_resolve_pass(PassSimple &pass, SceneResources &resource
{
if (cavity_enabled_) {
pass.bind_ubo("cavity_samples", samples_buf);
pass.bind_texture("jitter_tx", &resources.jitter_tx, eGPUSamplerState::GPU_SAMPLER_REPEAT);
pass.bind_texture("jitter_tx",
&resources.jitter_tx,
{GPU_SAMPLER_FILTERING_DEFAULT,
GPU_SAMPLER_EXTEND_MODE_REPEAT,
GPU_SAMPLER_EXTEND_MODE_REPEAT});
}
if (curvature_enabled_) {
pass.bind_texture("object_id_tx", &resources.object_id_tx);

View File

@ -173,7 +173,7 @@ void DofPass::sync(SceneResources &resources)
return;
}
eGPUSamplerState sampler_state = GPU_SAMPLER_FILTER | GPU_SAMPLER_MIPMAP;
GPUSamplerState sampler_state = {GPU_SAMPLER_FILTERING_LINEAR | GPU_SAMPLER_FILTERING_MIPMAP};
down_ps_.init();
down_ps_.state_set(DRW_STATE_WRITE_COLOR);

View File

@ -144,8 +144,12 @@ static void workbench_cache_texpaint_populate(WORKBENCH_PrivateData *wpd, Object
struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob);
if (geom) {
Image *ima = imapaint->canvas;
eGPUSamplerState state = GPU_SAMPLER_REPEAT;
SET_FLAG_FROM_TEST(state, imapaint->interp == IMAGEPAINT_INTERP_LINEAR, GPU_SAMPLER_FILTER);
const GPUSamplerFiltering filtering = imapaint->interp == IMAGEPAINT_INTERP_LINEAR ?
GPU_SAMPLER_FILTERING_LINEAR :
GPU_SAMPLER_FILTERING_DEFAULT;
GPUSamplerState state = {
filtering, GPU_SAMPLER_EXTEND_MODE_REPEAT, GPU_SAMPLER_EXTEND_MODE_REPEAT};
DRWShadingGroup *grp = workbench_image_setup(wpd, ob, 0, ima, NULL, state);
workbench_object_drawcall(grp, geom, ob);
@ -159,7 +163,8 @@ static void workbench_cache_texpaint_populate(WORKBENCH_PrivateData *wpd, Object
if (geoms[i] == NULL) {
continue;
}
DRWShadingGroup *grp = workbench_image_setup(wpd, ob, i + 1, NULL, NULL, 0);
DRWShadingGroup *grp = workbench_image_setup(
wpd, ob, i + 1, NULL, NULL, GPU_SAMPLER_DEFAULT);
workbench_object_drawcall(grp, geoms[i], ob);
}
}
@ -224,8 +229,9 @@ static void workbench_cache_hair_populate(WORKBENCH_PrivateData *wpd,
const ImagePaintSettings *imapaint = use_texpaint_mode ? &scene->toolsettings->imapaint : NULL;
Image *ima = (imapaint && imapaint->mode == IMAGEPAINT_MODE_IMAGE) ? imapaint->canvas : NULL;
eGPUSamplerState state = 0;
state |= (imapaint && imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? GPU_SAMPLER_FILTER : 0;
GPUSamplerState state = {imapaint && imapaint->interp == IMAGEPAINT_INTERP_LINEAR ?
GPU_SAMPLER_FILTERING_LINEAR :
GPU_SAMPLER_FILTERING_DEFAULT};
DRWShadingGroup *grp = (use_texpaint_mode) ?
workbench_image_hair_setup(wpd, ob, matnr, ima, NULL, state) :
workbench_material_hair_setup(wpd, ob, matnr, color_type);

View File

@ -217,7 +217,7 @@ class Instance {
::Image *image = nullptr;
ImageUser *iuser = nullptr;
eGPUSamplerState sampler_state = eGPUSamplerState::GPU_SAMPLER_DEFAULT;
GPUSamplerState sampler_state = GPUSamplerState::default_sampler();
if (object_state.color_type == V3D_SHADING_TEXTURE_COLOR) {
get_material_image(ob_ref.object, i + 1, image, iuser, sampler_state);
}
@ -284,7 +284,7 @@ class Instance {
GPUBatch *batch,
ResourceHandle handle,
::Image *image = nullptr,
eGPUSamplerState sampler_state = GPU_SAMPLER_DEFAULT,
GPUSamplerState sampler_state = GPUSamplerState::default_sampler(),
ImageUser *iuser = nullptr)
{
const bool in_front = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0;

View File

@ -86,10 +86,10 @@ BLI_INLINE Material *workbench_object_material_get(Object *ob, int mat_nr)
}
BLI_INLINE void workbench_material_get_image(
Object *ob, int mat_nr, Image **r_image, ImageUser **r_iuser, eGPUSamplerState *r_sampler)
Object *ob, int mat_nr, Image **r_image, ImageUser **r_iuser, GPUSamplerState *r_sampler)
{
const bNode *node;
*r_sampler = eGPUSamplerState(0);
*r_sampler = GPUSamplerState::default_sampler();
ED_object_get_active_image(ob, mat_nr, r_image, r_iuser, &node, nullptr);
if (node && *r_image) {
@ -97,19 +97,32 @@ BLI_INLINE void workbench_material_get_image(
case SH_NODE_TEX_IMAGE: {
const NodeTexImage *storage = static_cast<NodeTexImage *>(node->storage);
const bool use_filter = (storage->interpolation != SHD_INTERP_CLOSEST);
const bool use_mirror = (storage->extension == SHD_IMAGE_EXTENSION_MIRROR);
const bool use_repeat = use_mirror || (storage->extension == SHD_IMAGE_EXTENSION_REPEAT);
const bool use_clip = (storage->extension == SHD_IMAGE_EXTENSION_CLIP);
SET_FLAG_FROM_TEST(*r_sampler, use_filter, GPU_SAMPLER_FILTER);
SET_FLAG_FROM_TEST(*r_sampler, use_repeat, GPU_SAMPLER_REPEAT);
SET_FLAG_FROM_TEST(*r_sampler, use_clip, GPU_SAMPLER_CLAMP_BORDER);
SET_FLAG_FROM_TEST(*r_sampler, use_mirror, GPU_SAMPLER_MIRROR_REPEAT);
r_sampler->set_filtering_flag_from_test(GPU_SAMPLER_FILTERING_LINEAR, use_filter);
switch (storage->extension) {
case SHD_IMAGE_EXTENSION_EXTEND:
default:
r_sampler->extend_x = GPU_SAMPLER_EXTEND_MODE_EXTEND;
r_sampler->extend_yz = GPU_SAMPLER_EXTEND_MODE_EXTEND;
break;
case SHD_IMAGE_EXTENSION_REPEAT:
r_sampler->extend_x = GPU_SAMPLER_EXTEND_MODE_REPEAT;
r_sampler->extend_yz = GPU_SAMPLER_EXTEND_MODE_REPEAT;
break;
case SHD_IMAGE_EXTENSION_MIRROR:
r_sampler->extend_x = GPU_SAMPLER_EXTEND_MODE_MIRRORED_REPEAT;
r_sampler->extend_yz = GPU_SAMPLER_EXTEND_MODE_MIRRORED_REPEAT;
break;
case SHD_IMAGE_EXTENSION_CLIP:
r_sampler->extend_x = GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER;
r_sampler->extend_yz = GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER;
break;
}
break;
}
case SH_NODE_TEX_ENVIRONMENT: {
const NodeTexEnvironment *storage = static_cast<NodeTexEnvironment *>(node->storage);
const bool use_filter = (storage->interpolation != SHD_INTERP_CLOSEST);
SET_FLAG_FROM_TEST(*r_sampler, use_filter, GPU_SAMPLER_FILTER);
r_sampler->set_filtering_flag_from_test(GPU_SAMPLER_FILTERING_LINEAR, use_filter);
break;
}
default:
@ -157,7 +170,7 @@ DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd,
{
Image *ima = nullptr;
ImageUser *iuser = nullptr;
eGPUSamplerState sampler;
GPUSamplerState sampler;
const bool infront = (ob->dtx & OB_DRAW_IN_FRONT) != 0;
if (color_type == V3D_SHADING_TEXTURE_COLOR) {
@ -240,7 +253,7 @@ DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
int mat_nr,
Image *ima,
ImageUser *iuser,
eGPUSamplerState sampler,
GPUSamplerState sampler,
eWORKBENCH_DataType datatype)
{
GPUTexture *tex = nullptr, *tex_tile_data = nullptr;

View File

@ -61,7 +61,7 @@ void get_material_image(Object *ob,
int material_index,
::Image *&image,
ImageUser *&iuser,
eGPUSamplerState &sampler_state)
GPUSamplerState &sampler_state)
{
const ::bNode *node = nullptr;
@ -71,19 +71,32 @@ void get_material_image(Object *ob,
case SH_NODE_TEX_IMAGE: {
const NodeTexImage *storage = static_cast<NodeTexImage *>(node->storage);
const bool use_filter = (storage->interpolation != SHD_INTERP_CLOSEST);
const bool use_mirror = (storage->extension == SHD_IMAGE_EXTENSION_MIRROR);
const bool use_repeat = use_mirror || (storage->extension == SHD_IMAGE_EXTENSION_REPEAT);
const bool use_clip = (storage->extension == SHD_IMAGE_EXTENSION_CLIP);
SET_FLAG_FROM_TEST(sampler_state, use_filter, GPU_SAMPLER_FILTER);
SET_FLAG_FROM_TEST(sampler_state, use_repeat, GPU_SAMPLER_REPEAT);
SET_FLAG_FROM_TEST(sampler_state, use_clip, GPU_SAMPLER_CLAMP_BORDER);
SET_FLAG_FROM_TEST(sampler_state, use_mirror, GPU_SAMPLER_MIRROR_REPEAT);
sampler_state.set_filtering_flag_from_test(GPU_SAMPLER_FILTERING_LINEAR, use_filter);
switch (storage->extension) {
case SHD_IMAGE_EXTENSION_EXTEND:
default:
sampler_state.extend_x = GPU_SAMPLER_EXTEND_MODE_EXTEND;
sampler_state.extend_yz = GPU_SAMPLER_EXTEND_MODE_EXTEND;
break;
case SHD_IMAGE_EXTENSION_REPEAT:
sampler_state.extend_x = GPU_SAMPLER_EXTEND_MODE_REPEAT;
sampler_state.extend_yz = GPU_SAMPLER_EXTEND_MODE_REPEAT;
break;
case SHD_IMAGE_EXTENSION_MIRROR:
sampler_state.extend_x = GPU_SAMPLER_EXTEND_MODE_MIRRORED_REPEAT;
sampler_state.extend_yz = GPU_SAMPLER_EXTEND_MODE_MIRRORED_REPEAT;
break;
case SHD_IMAGE_EXTENSION_CLIP:
sampler_state.extend_x = GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER;
sampler_state.extend_yz = GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER;
break;
}
break;
}
case SH_NODE_TEX_ENVIRONMENT: {
const NodeTexEnvironment *storage = static_cast<NodeTexEnvironment *>(node->storage);
const bool use_filter = (storage->interpolation != SHD_INTERP_CLOSEST);
SET_FLAG_FROM_TEST(sampler_state, use_filter, GPU_SAMPLER_FILTER);
sampler_state.set_filtering_flag_from_test(GPU_SAMPLER_FILTERING_LINEAR, use_filter);
break;
}
default:

View File

@ -60,7 +60,7 @@ void MeshPass::draw(ObjectRef &ref,
ResourceHandle handle,
uint material_index,
::Image *image /* = nullptr */,
eGPUSamplerState sampler_state /* = GPU_SAMPLER_DEFAULT */,
GPUSamplerState sampler_state /* = GPUSamplerState::default_sampler() */,
ImageUser *iuser /* = nullptr */)
{
is_empty_ = false;

View File

@ -499,7 +499,7 @@ DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
int mat_nr,
Image *ima,
ImageUser *iuser,
eGPUSamplerState sampler,
GPUSamplerState sampler,
eWORKBENCH_DataType datatype);
#define WORKBENCH_OBJECT_DATATYPE(ob) \

View File

@ -57,7 +57,7 @@ void get_material_image(Object *ob,
int material_index,
::Image *&image,
ImageUser *&iuser,
eGPUSamplerState &sampler_state);
GPUSamplerState &sampler_state);
struct SceneState {
Scene *scene = nullptr;
@ -106,7 +106,7 @@ struct ObjectState {
bool sculpt_pbvh = false;
bool texture_paint_mode = false;
::Image *image_paint_override = nullptr;
eGPUSamplerState override_sampler_state = GPU_SAMPLER_DEFAULT;
GPUSamplerState override_sampler_state = GPUSamplerState::default_sampler();
bool draw_shadow = false;
bool use_per_material_batches = false;
@ -186,7 +186,7 @@ class MeshPass : public PassMain {
ResourceHandle handle,
uint material_index,
::Image *image = nullptr,
eGPUSamplerState sampler_state = eGPUSamplerState::GPU_SAMPLER_DEFAULT,
GPUSamplerState sampler_state = GPUSamplerState::default_sampler(),
ImageUser *iuser = nullptr);
};

View File

@ -199,7 +199,7 @@ ObjectState::ObjectState(const SceneState &scene_state, Object *ob)
sculpt_pbvh = false;
texture_paint_mode = false;
image_paint_override = nullptr;
override_sampler_state = GPU_SAMPLER_DEFAULT;
override_sampler_state = GPUSamplerState::default_sampler();
draw_shadow = false;
const DRWContextState *draw_ctx = DRW_context_state_get();
@ -283,10 +283,11 @@ ObjectState::ObjectState(const SceneState &scene_state, Object *ob)
const ImagePaintSettings *imapaint = &scene_state.scene->toolsettings->imapaint;
if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
image_paint_override = imapaint->canvas;
override_sampler_state = GPU_SAMPLER_REPEAT;
SET_FLAG_FROM_TEST(override_sampler_state,
imapaint->interp == IMAGEPAINT_INTERP_LINEAR,
GPU_SAMPLER_FILTER);
override_sampler_state.extend_x = GPU_SAMPLER_EXTEND_MODE_REPEAT;
override_sampler_state.extend_yz = GPU_SAMPLER_EXTEND_MODE_REPEAT;
const bool use_linear_filter = imapaint->interp == IMAGEPAINT_INTERP_LINEAR;
override_sampler_state.set_filtering_flag_from_test(GPU_SAMPLER_FILTERING_LINEAR,
use_linear_filter);
}
}
}

View File

@ -534,11 +534,11 @@ void DRW_shgroup_clear_framebuffer(DRWShadingGroup *shgroup,
void DRW_shgroup_uniform_texture_ex(DRWShadingGroup *shgroup,
const char *name,
const struct GPUTexture *tex,
eGPUSamplerState sampler_state);
GPUSamplerState sampler_state);
void DRW_shgroup_uniform_texture_ref_ex(DRWShadingGroup *shgroup,
const char *name,
GPUTexture **tex,
eGPUSamplerState sampler_state);
GPUSamplerState sampler_state);
void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup,
const char *name,
const struct GPUTexture *tex);

View File

@ -318,7 +318,7 @@ static DRWVolumeGrid *volume_grid_cache_get(const Volume *volume,
* GL_MAX_3D_TEXTURE_SIZE. */
if (cache_grid->texture != nullptr) {
GPU_texture_swizzle_set(cache_grid->texture, (channels == 3) ? "rgb1" : "rrr1");
GPU_texture_wrap_mode(cache_grid->texture, false, false);
GPU_texture_extend_mode(cache_grid->texture, GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER);
BKE_volume_dense_float_grid_clear(&dense_grid);
}
else {

View File

@ -262,8 +262,7 @@ std::string ResourceBind::serialize() const
switch (type) {
case Type::Sampler:
return std::string(".bind_texture") + (is_reference ? "_ref" : "") + "(" +
std::to_string(slot) +
(sampler != GPU_SAMPLER_MAX ? ", sampler=" + std::to_string(sampler) : "") + ")";
std::to_string(slot) + ", sampler=" + sampler.to_string() + ")";
case Type::BufferSampler:
return std::string(".bind_vertbuf_as_texture") + (is_reference ? "_ref" : "") + "(" +
std::to_string(slot) + ")";

View File

@ -134,7 +134,7 @@ struct FramebufferBind {
};
struct ResourceBind {
eGPUSamplerState sampler;
GPUSamplerState sampler;
int slot;
bool is_reference;
@ -191,9 +191,9 @@ struct ResourceBind {
: slot(slot_), is_reference(false), type(Type::Image), texture(draw::as_texture(res)){};
ResourceBind(int slot_, draw::Image **res)
: slot(slot_), is_reference(true), type(Type::Image), texture_ref(draw::as_texture(res)){};
ResourceBind(int slot_, GPUTexture *res, eGPUSamplerState state)
ResourceBind(int slot_, GPUTexture *res, GPUSamplerState state)
: sampler(state), slot(slot_), is_reference(false), type(Type::Sampler), texture(res){};
ResourceBind(int slot_, GPUTexture **res, eGPUSamplerState state)
ResourceBind(int slot_, GPUTexture **res, GPUSamplerState state)
: sampler(state), slot(slot_), is_reference(true), type(Type::Sampler), texture_ref(res){};
ResourceBind(int slot_, GPUVertBuf *res)
: slot(slot_), is_reference(false), type(Type::BufferSampler), vertex_buf(res){};

View File

@ -362,7 +362,7 @@ struct DRWUniform {
GPUTexture *texture;
GPUTexture **texture_ref;
};
eGPUSamplerState sampler_state;
GPUSamplerState sampler_state;
};
/* DRW_UNIFORM_BLOCK */
union {

View File

@ -169,7 +169,7 @@ static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup,
int loc,
DRWUniformType type,
const void *value,
eGPUSamplerState sampler_state,
GPUSamplerState sampler_state,
int length,
int arraysize)
{
@ -247,13 +247,13 @@ static void drw_shgroup_uniform(DRWShadingGroup *shgroup,
DRW_UNIFORM_TEXTURE_REF));
int location = GPU_shader_get_uniform(shgroup->shader, name);
drw_shgroup_uniform_create_ex(
shgroup, location, type, value, GPU_SAMPLER_DEFAULT, length, arraysize);
shgroup, location, type, value, GPUSamplerState::default_sampler(), length, arraysize);
}
void DRW_shgroup_uniform_texture_ex(DRWShadingGroup *shgroup,
const char *name,
const GPUTexture *tex,
eGPUSamplerState sampler_state)
GPUSamplerState sampler_state)
{
BLI_assert(tex != nullptr);
int loc = GPU_shader_get_sampler_binding(shgroup->shader, name);
@ -262,13 +262,13 @@ void DRW_shgroup_uniform_texture_ex(DRWShadingGroup *shgroup,
void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex)
{
DRW_shgroup_uniform_texture_ex(shgroup, name, tex, GPU_SAMPLER_MAX);
DRW_shgroup_uniform_texture_ex(shgroup, name, tex, GPUSamplerState::internal_sampler());
}
void DRW_shgroup_uniform_texture_ref_ex(DRWShadingGroup *shgroup,
const char *name,
GPUTexture **tex,
eGPUSamplerState sampler_state)
GPUSamplerState sampler_state)
{
BLI_assert(tex != nullptr);
int loc = GPU_shader_get_sampler_binding(shgroup->shader, name);
@ -277,14 +277,15 @@ void DRW_shgroup_uniform_texture_ref_ex(DRWShadingGroup *shgroup,
void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex)
{
DRW_shgroup_uniform_texture_ref_ex(shgroup, name, tex, GPU_SAMPLER_MAX);
DRW_shgroup_uniform_texture_ref_ex(shgroup, name, tex, GPUSamplerState::internal_sampler());
}
void DRW_shgroup_uniform_image(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex)
{
BLI_assert(tex != nullptr);
int loc = GPU_shader_get_sampler_binding(shgroup->shader, name);
drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_IMAGE, tex, GPU_SAMPLER_DEFAULT, 0, 1);
drw_shgroup_uniform_create_ex(
shgroup, loc, DRW_UNIFORM_IMAGE, tex, GPUSamplerState::default_sampler(), 0, 1);
}
void DRW_shgroup_uniform_image_ref(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex)
@ -292,7 +293,7 @@ void DRW_shgroup_uniform_image_ref(DRWShadingGroup *shgroup, const char *name, G
BLI_assert(tex != nullptr);
int loc = GPU_shader_get_sampler_binding(shgroup->shader, name);
drw_shgroup_uniform_create_ex(
shgroup, loc, DRW_UNIFORM_IMAGE_REF, tex, GPU_SAMPLER_DEFAULT, 0, 1);
shgroup, loc, DRW_UNIFORM_IMAGE_REF, tex, GPUSamplerState::default_sampler(), 0, 1);
}
void DRW_shgroup_uniform_block_ex(DRWShadingGroup *shgroup,
@ -313,7 +314,8 @@ void DRW_shgroup_uniform_block_ex(DRWShadingGroup *shgroup,
#endif
return;
}
drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_BLOCK, ubo, GPU_SAMPLER_DEFAULT, 0, 1);
drw_shgroup_uniform_create_ex(
shgroup, loc, DRW_UNIFORM_BLOCK, ubo, GPUSamplerState::default_sampler(), 0, 1);
}
void DRW_shgroup_uniform_block_ref_ex(DRWShadingGroup *shgroup,
@ -335,7 +337,7 @@ void DRW_shgroup_uniform_block_ref_ex(DRWShadingGroup *shgroup,
return;
}
drw_shgroup_uniform_create_ex(
shgroup, loc, DRW_UNIFORM_BLOCK_REF, ubo, GPU_SAMPLER_DEFAULT, 0, 1);
shgroup, loc, DRW_UNIFORM_BLOCK_REF, ubo, GPUSamplerState::default_sampler(), 0, 1);
}
void DRW_shgroup_storage_block_ex(DRWShadingGroup *shgroup,
@ -358,7 +360,7 @@ void DRW_shgroup_storage_block_ex(DRWShadingGroup *shgroup,
return;
}
drw_shgroup_uniform_create_ex(
shgroup, loc, DRW_UNIFORM_STORAGE_BLOCK, ssbo, GPU_SAMPLER_DEFAULT, 0, 1);
shgroup, loc, DRW_UNIFORM_STORAGE_BLOCK, ssbo, GPUSamplerState::default_sampler(), 0, 1);
}
void DRW_shgroup_storage_block_ref_ex(DRWShadingGroup *shgroup,
@ -381,7 +383,7 @@ void DRW_shgroup_storage_block_ref_ex(DRWShadingGroup *shgroup,
return;
}
drw_shgroup_uniform_create_ex(
shgroup, loc, DRW_UNIFORM_STORAGE_BLOCK_REF, ssbo, GPU_SAMPLER_DEFAULT, 0, 1);
shgroup, loc, DRW_UNIFORM_STORAGE_BLOCK_REF, ssbo, GPUSamplerState::default_sampler(), 0, 1);
}
void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup,
@ -530,8 +532,13 @@ void DRW_shgroup_uniform_mat4_copy(DRWShadingGroup *shgroup,
* and array-size used to determine the number of elements
* copied in draw_update_uniforms. */
for (int i = 0; i < 4; i++) {
drw_shgroup_uniform_create_ex(
shgroup, location, DRW_UNIFORM_FLOAT_COPY, &value[i], GPU_SAMPLER_DEFAULT, 4, 4);
drw_shgroup_uniform_create_ex(shgroup,
location,
DRW_UNIFORM_FLOAT_COPY,
&value[i],
GPUSamplerState::default_sampler(),
4,
4);
}
}
@ -555,7 +562,7 @@ void DRW_shgroup_vertex_buffer_ex(DRWShadingGroup *shgroup,
location,
DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE,
vertex_buffer,
GPU_SAMPLER_DEFAULT,
GPUSamplerState::default_sampler(),
0,
1);
}
@ -580,7 +587,7 @@ void DRW_shgroup_vertex_buffer_ref_ex(DRWShadingGroup *shgroup,
location,
DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE_REF,
vertex_buffer,
GPU_SAMPLER_DEFAULT,
GPUSamplerState::default_sampler(),
0,
1);
}
@ -597,7 +604,7 @@ void DRW_shgroup_buffer_texture(DRWShadingGroup *shgroup,
location,
DRW_UNIFORM_VERTEX_BUFFER_AS_TEXTURE,
vertex_buffer,
GPU_SAMPLER_DEFAULT,
GPUSamplerState::default_sampler(),
0,
1);
}
@ -614,7 +621,7 @@ void DRW_shgroup_buffer_texture_ref(DRWShadingGroup *shgroup,
location,
DRW_UNIFORM_VERTEX_BUFFER_AS_TEXTURE_REF,
vertex_buffer,
GPU_SAMPLER_DEFAULT,
GPUSamplerState::default_sampler(),
0,
1);
}
@ -698,7 +705,7 @@ static void drw_call_obinfos_init(DRWObjectInfos *ob_infos, Object *ob)
drw_call_calc_orco(ob, ob_infos->orcotexfac);
/* Random float value. */
uint random = (DST.dupli_source) ?
DST.dupli_source->random_id :
DST.dupli_source->random_id :
/* TODO(fclem): this is rather costly to do at runtime. Maybe we can
* put it in ob->runtime and make depsgraph ensure it is up to date. */
BLI_hash_int_2d(BLI_hash_string(ob->id.name + 2), 0);
@ -1653,23 +1660,43 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader)
}
if (chunkid_location != -1) {
drw_shgroup_uniform_create_ex(
shgroup, chunkid_location, DRW_UNIFORM_RESOURCE_CHUNK, nullptr, GPU_SAMPLER_DEFAULT, 0, 1);
drw_shgroup_uniform_create_ex(shgroup,
chunkid_location,
DRW_UNIFORM_RESOURCE_CHUNK,
nullptr,
GPUSamplerState::default_sampler(),
0,
1);
}
if (resourceid_location != -1) {
drw_shgroup_uniform_create_ex(
shgroup, resourceid_location, DRW_UNIFORM_RESOURCE_ID, nullptr, GPU_SAMPLER_DEFAULT, 0, 1);
drw_shgroup_uniform_create_ex(shgroup,
resourceid_location,
DRW_UNIFORM_RESOURCE_ID,
nullptr,
GPUSamplerState::default_sampler(),
0,
1);
}
if (baseinst_location != -1) {
drw_shgroup_uniform_create_ex(
shgroup, baseinst_location, DRW_UNIFORM_BASE_INSTANCE, nullptr, GPU_SAMPLER_DEFAULT, 0, 1);
drw_shgroup_uniform_create_ex(shgroup,
baseinst_location,
DRW_UNIFORM_BASE_INSTANCE,
nullptr,
GPUSamplerState::default_sampler(),
0,
1);
}
if (model_ubo_location != -1) {
drw_shgroup_uniform_create_ex(
shgroup, model_ubo_location, DRW_UNIFORM_BLOCK_OBMATS, nullptr, GPU_SAMPLER_DEFAULT, 0, 1);
drw_shgroup_uniform_create_ex(shgroup,
model_ubo_location,
DRW_UNIFORM_BLOCK_OBMATS,
nullptr,
GPUSamplerState::default_sampler(),
0,
1);
}
else {
/* NOTE: This is only here to support old hardware fallback where uniform buffer is still
@ -1677,23 +1704,33 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader)
int model = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL);
int modelinverse = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL_INV);
if (model != -1) {
drw_shgroup_uniform_create_ex(
shgroup, model, DRW_UNIFORM_MODEL_MATRIX, nullptr, GPU_SAMPLER_DEFAULT, 0, 1);
drw_shgroup_uniform_create_ex(shgroup,
model,
DRW_UNIFORM_MODEL_MATRIX,
nullptr,
GPUSamplerState::default_sampler(),
0,
1);
}
if (modelinverse != -1) {
drw_shgroup_uniform_create_ex(shgroup,
modelinverse,
DRW_UNIFORM_MODEL_MATRIX_INVERSE,
nullptr,
GPU_SAMPLER_DEFAULT,
GPUSamplerState::default_sampler(),
0,
1);
}
}
if (info_ubo_location != -1) {
drw_shgroup_uniform_create_ex(
shgroup, info_ubo_location, DRW_UNIFORM_BLOCK_OBINFOS, nullptr, GPU_SAMPLER_DEFAULT, 0, 1);
drw_shgroup_uniform_create_ex(shgroup,
info_ubo_location,
DRW_UNIFORM_BLOCK_OBINFOS,
nullptr,
GPUSamplerState::default_sampler(),
0,
1);
/* Abusing this loc to tell shgroup we need the obinfos. */
shgroup->objectinfo = 1;
@ -1703,8 +1740,13 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader)
}
if (view_ubo_location != -1) {
drw_shgroup_uniform_create_ex(
shgroup, view_ubo_location, DRW_UNIFORM_BLOCK, G_draw.view_ubo, GPU_SAMPLER_DEFAULT, 0, 1);
drw_shgroup_uniform_create_ex(shgroup,
view_ubo_location,
DRW_UNIFORM_BLOCK,
G_draw.view_ubo,
GPUSamplerState::default_sampler(),
0,
1);
}
if (clipping_ubo_location != -1) {
@ -1712,7 +1754,7 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader)
clipping_ubo_location,
DRW_UNIFORM_BLOCK,
G_draw.clipping_ubo,
GPU_SAMPLER_DEFAULT,
GPUSamplerState::default_sampler(),
0,
1);
}
@ -1767,7 +1809,7 @@ static DRWShadingGroup *drw_shgroup_material_create_ex(GPUPass *gpupass, DRWPass
static void drw_shgroup_material_texture(DRWShadingGroup *grp,
GPUTexture *gputex,
const char *name,
eGPUSamplerState state)
GPUSamplerState state)
{
DRW_shgroup_uniform_texture_ex(grp, name, gputex, state);
@ -1788,16 +1830,13 @@ void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, GPUMaterial *mater
ImageUser *iuser = tex->iuser_available ? &tex->iuser : nullptr;
if (tex->tiled_mapping_name[0]) {
gputex = BKE_image_get_gpu_tiles(tex->ima, iuser, nullptr);
drw_shgroup_material_texture(
grp, gputex, tex->sampler_name, eGPUSamplerState(tex->sampler_state));
drw_shgroup_material_texture(grp, gputex, tex->sampler_name, tex->sampler_state);
gputex = BKE_image_get_gpu_tilemap(tex->ima, iuser, nullptr);
drw_shgroup_material_texture(
grp, gputex, tex->tiled_mapping_name, eGPUSamplerState(tex->sampler_state));
drw_shgroup_material_texture(grp, gputex, tex->tiled_mapping_name, tex->sampler_state);
}
else {
gputex = BKE_image_get_gpu_texture(tex->ima, iuser, nullptr);
drw_shgroup_material_texture(
grp, gputex, tex->sampler_name, eGPUSamplerState(tex->sampler_state));
drw_shgroup_material_texture(grp, gputex, tex->sampler_name, tex->sampler_state);
}
}
else if (tex->colorband) {
@ -1806,8 +1845,7 @@ void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, GPUMaterial *mater
}
else if (tex->sky) {
/* Sky */
DRW_shgroup_uniform_texture_ex(
grp, tex->sampler_name, *tex->sky, eGPUSamplerState(tex->sampler_state));
DRW_shgroup_uniform_texture_ex(grp, tex->sampler_name, *tex->sky, tex->sampler_state);
}
}
@ -1820,14 +1858,14 @@ void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, GPUMaterial *mater
if (uattrs != nullptr) {
int loc = GPU_shader_get_ubo_binding(grp->shader, GPU_ATTRIBUTE_UBO_BLOCK_NAME);
drw_shgroup_uniform_create_ex(
grp, loc, DRW_UNIFORM_BLOCK_OBATTRS, uattrs, GPU_SAMPLER_DEFAULT, 0, 1);
grp, loc, DRW_UNIFORM_BLOCK_OBATTRS, uattrs, GPUSamplerState::default_sampler(), 0, 1);
grp->uniform_attrs = uattrs;
}
if (GPU_material_layer_attributes(material) != nullptr) {
int loc = GPU_shader_get_ubo_binding(grp->shader, GPU_LAYER_ATTRIBUTE_UBO_BLOCK_NAME);
drw_shgroup_uniform_create_ex(
grp, loc, DRW_UNIFORM_BLOCK_VLATTRS, nullptr, GPU_SAMPLER_DEFAULT, 0, 1);
grp, loc, DRW_UNIFORM_BLOCK_VLATTRS, nullptr, GPUSamplerState::default_sampler(), 0, 1);
}
}
@ -1872,8 +1910,13 @@ DRWShadingGroup *DRW_shgroup_transform_feedback_create(GPUShader *shader,
BLI_assert(tf_target != nullptr);
DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
drw_shgroup_init(shgroup, shader);
drw_shgroup_uniform_create_ex(
shgroup, 0, DRW_UNIFORM_TFEEDBACK_TARGET, tf_target, GPU_SAMPLER_DEFAULT, 0, 1);
drw_shgroup_uniform_create_ex(shgroup,
0,
DRW_UNIFORM_TFEEDBACK_TARGET,
tf_target,
GPUSamplerState::default_sampler(),
0,
1);
return shgroup;
}

View File

@ -60,7 +60,8 @@ void drw_texture_set_parameters(GPUTexture *tex, DRWTextureFlag flags)
GPU_texture_filter_mode(tex, flags & DRW_TEX_FILTER);
}
GPU_texture_anisotropic_filter(tex, false);
GPU_texture_wrap_mode(tex, flags & DRW_TEX_WRAP, true);
GPU_texture_extend_mode(
tex, flags & DRW_TEX_WRAP ? GPU_SAMPLER_EXTEND_MODE_REPEAT : GPU_SAMPLER_EXTEND_MODE_EXTEND);
GPU_texture_compare_mode(tex, flags & DRW_TEX_COMPARE);
}

View File

@ -117,8 +117,8 @@ class PassBase {
friend Manager;
friend DrawCommandBuf;
/** Will use texture own sampler state. */
static constexpr eGPUSamplerState sampler_auto = GPU_SAMPLER_MAX;
/** Will use texture own internal sampler state. */
static constexpr GPUSamplerState sampler_auto = GPUSamplerState::internal_sampler();
protected:
/** Highest level of the command stream. Split command stream in different command types. */
@ -287,12 +287,12 @@ class PassBase {
void bind_image(const char *name, GPUTexture **image);
void bind_image(int slot, GPUTexture *image);
void bind_image(int slot, GPUTexture **image);
void bind_texture(const char *name, GPUTexture *texture, eGPUSamplerState state = sampler_auto);
void bind_texture(const char *name, GPUTexture **texture, eGPUSamplerState state = sampler_auto);
void bind_texture(const char *name, GPUTexture *texture, GPUSamplerState state = sampler_auto);
void bind_texture(const char *name, GPUTexture **texture, GPUSamplerState state = sampler_auto);
void bind_texture(const char *name, GPUVertBuf *buffer);
void bind_texture(const char *name, GPUVertBuf **buffer);
void bind_texture(int slot, GPUTexture *texture, eGPUSamplerState state = sampler_auto);
void bind_texture(int slot, GPUTexture **texture, eGPUSamplerState state = sampler_auto);
void bind_texture(int slot, GPUTexture *texture, GPUSamplerState state = sampler_auto);
void bind_texture(int slot, GPUTexture **texture, GPUSamplerState state = sampler_auto);
void bind_texture(int slot, GPUVertBuf *buffer);
void bind_texture(int slot, GPUVertBuf **buffer);
void bind_ssbo(const char *name, GPUStorageBuf *buffer);
@ -836,16 +836,16 @@ template<class T> inline void PassBase<T>::material_set(Manager &manager, GPUMat
if (tex->tiled_mapping_name[0]) {
GPUTexture *tiles = BKE_image_get_gpu_tiles(tex->ima, iuser, nullptr);
manager.acquire_texture(tiles);
bind_texture(tex->sampler_name, tiles, (eGPUSamplerState)tex->sampler_state);
bind_texture(tex->sampler_name, tiles, tex->sampler_state);
GPUTexture *tile_map = BKE_image_get_gpu_tilemap(tex->ima, iuser, nullptr);
manager.acquire_texture(tile_map);
bind_texture(tex->tiled_mapping_name, tile_map, (eGPUSamplerState)tex->sampler_state);
bind_texture(tex->tiled_mapping_name, tile_map, tex->sampler_state);
}
else {
GPUTexture *texture = BKE_image_get_gpu_texture(tex->ima, iuser, nullptr);
manager.acquire_texture(texture);
bind_texture(tex->sampler_name, texture, (eGPUSamplerState)tex->sampler_state);
bind_texture(tex->sampler_name, texture, tex->sampler_state);
}
}
else if (tex->colorband) {
@ -912,9 +912,7 @@ template<class T> inline void PassBase<T>::bind_ubo(const char *name, GPUUniform
}
template<class T>
inline void PassBase<T>::bind_texture(const char *name,
GPUTexture *texture,
eGPUSamplerState state)
inline void PassBase<T>::bind_texture(const char *name, GPUTexture *texture, GPUSamplerState state)
{
this->bind_texture(GPU_shader_get_sampler_binding(shader_, name), texture, state);
}
@ -981,7 +979,7 @@ template<class T> inline void PassBase<T>::bind_ubo(int slot, GPUUniformBuf *buf
}
template<class T>
inline void PassBase<T>::bind_texture(int slot, GPUTexture *texture, eGPUSamplerState state)
inline void PassBase<T>::bind_texture(int slot, GPUTexture *texture, GPUSamplerState state)
{
create_command(Type::ResourceBind).resource_bind = {slot, texture, state};
}
@ -1014,7 +1012,7 @@ template<class T> inline void PassBase<T>::bind_ubo(const char *name, GPUUniform
template<class T>
inline void PassBase<T>::bind_texture(const char *name,
GPUTexture **texture,
eGPUSamplerState state)
GPUSamplerState state)
{
this->bind_texture(GPU_shader_get_sampler_binding(shader_, name), texture, state);
}
@ -1036,7 +1034,7 @@ template<class T> inline void PassBase<T>::bind_ubo(int slot, GPUUniformBuf **bu
}
template<class T>
inline void PassBase<T>::bind_texture(int slot, GPUTexture **texture, eGPUSamplerState state)
inline void PassBase<T>::bind_texture(int slot, GPUTexture **texture, GPUSamplerState state)
{
create_command(Type::ResourceBind).resource_bind = {slot, texture, state};
}

View File

@ -74,8 +74,8 @@ static void drw_volume_globals_init()
"dummy_zero", 1, 1, 1, 1, GPU_RGBA8, GPU_TEXTURE_USAGE_SHADER_READ, zero);
g_data.dummy_one = GPU_texture_create_3d(
"dummy_one", 1, 1, 1, 1, GPU_RGBA8, GPU_TEXTURE_USAGE_SHADER_READ, one);
GPU_texture_wrap_mode(g_data.dummy_zero, true, true);
GPU_texture_wrap_mode(g_data.dummy_one, true, true);
GPU_texture_extend_mode(g_data.dummy_zero, GPU_SAMPLER_EXTEND_MODE_REPEAT);
GPU_texture_extend_mode(g_data.dummy_one, GPU_SAMPLER_EXTEND_MODE_REPEAT);
memset(g_data.dummy_grid_mat, 0, sizeof(g_data.dummy_grid_mat));
}

View File

@ -1624,7 +1624,7 @@ static void icon_draw_cache_texture_flush_ex(GPUTexture *texture,
GPU_uniformbuf_bind(ubo, data_binding);
const int img_binding = GPU_shader_get_sampler_binding(shader, "image");
GPU_texture_bind_ex(texture, GPU_SAMPLER_ICON, img_binding);
GPU_texture_bind_ex(texture, GPUSamplerState::icon_sampler(), img_binding);
GPUBatch *quad = GPU_batch_preset_quad();
GPU_batch_set_shader(quad, shader);
@ -1816,7 +1816,7 @@ static void icon_draw_texture(float x,
GPU_shader_uniform_float_ex(shader, rect_geom_loc, 4, 1, geom_color);
GPU_shader_uniform_1f(shader, "text_width", text_width);
GPU_texture_bind_ex(texture, GPU_SAMPLER_ICON, img_binding);
GPU_texture_bind_ex(texture, GPUSamplerState::icon_sampler(), img_binding);
GPUBatch *quad = GPU_batch_preset_quad();
GPU_batch_set_shader(quad, shader);

View File

@ -92,7 +92,7 @@ void immDrawPixelsTexScaledFullSize(const IMMDrawPixelsTexState *state,
GPU_texture_update_mipmap_chain(tex);
GPU_texture_mipmap_mode(tex, true, true);
}
GPU_texture_wrap_mode(tex, false, true);
GPU_texture_extend_mode(tex, GPU_SAMPLER_EXTEND_MODE_EXTEND);
GPU_texture_bind(tex, 0);
@ -186,7 +186,7 @@ void immDrawPixelsTexTiled_scaling_clipping(IMMDrawPixelsTexState *state,
"immDrawPixels", tex_w, tex_h, 1, gpu_format, GPU_TEXTURE_USAGE_SHADER_READ, NULL);
GPU_texture_filter_mode(tex, use_filter);
GPU_texture_wrap_mode(tex, false, true);
GPU_texture_extend_mode(tex, GPU_SAMPLER_EXTEND_MODE_EXTEND);
GPU_texture_bind(tex, 0);

View File

@ -655,10 +655,11 @@ static bool paint_draw_tex_overlay(UnifiedPaintSettings *ups,
GPUTexture *texture = (primary) ? primary_snap.overlay_texture :
secondary_snap.overlay_texture;
eGPUSamplerState state = GPU_SAMPLER_FILTER;
state |= (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) ? GPU_SAMPLER_CLAMP_BORDER :
GPU_SAMPLER_REPEAT;
immBindTextureSampler("image", texture, state);
GPUSamplerExtendMode extend_mode = (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) ?
GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER :
GPU_SAMPLER_EXTEND_MODE_REPEAT;
immBindTextureSampler(
"image", texture, {GPU_SAMPLER_FILTERING_LINEAR, extend_mode, extend_mode});
/* Draw textured quad. */
immBegin(GPU_PRIM_TRI_FAN, 4);
@ -742,8 +743,11 @@ static bool paint_draw_cursor_overlay(
immUniformColor4fv(final_color);
/* Draw textured quad. */
immBindTextureSampler(
"image", cursor_snap.overlay_texture, GPU_SAMPLER_FILTER | GPU_SAMPLER_CLAMP_BORDER);
immBindTextureSampler("image",
cursor_snap.overlay_texture,
{GPU_SAMPLER_FILTERING_LINEAR,
GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER,
GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER});
immBegin(GPU_PRIM_TRI_FAN, 4);
immAttr2f(texCoord, 0.0f, 0.0f);

View File

@ -105,7 +105,7 @@ void immUniformArray4fv(const char *bare_name, const float *data, int count);
void immUniformMatrix4fv(const char *name, const float data[4][4]);
void immBindTexture(const char *name, GPUTexture *tex);
void immBindTextureSampler(const char *name, GPUTexture *tex, eGPUSamplerState state);
void immBindTextureSampler(const char *name, GPUTexture *tex, GPUSamplerState state);
void immBindUniformBuf(const char *name, GPUUniformBuf *ubo);
/* Convenience functions for setting "uniform vec4 color". */

View File

@ -14,7 +14,7 @@
#include "BLI_sys_types.h" /* for bool */
#include "GPU_shader.h" /* for GPUShaderCreateInfo */
#include "GPU_texture.h" /* for eGPUSamplerState */
#include "GPU_texture.h" /* for GPUSamplerState */
#ifdef __cplusplus
extern "C" {
@ -166,11 +166,11 @@ GPUNodeLink *GPU_layer_attribute(GPUMaterial *mat, const char *name);
GPUNodeLink *GPU_image(GPUMaterial *mat,
struct Image *ima,
struct ImageUser *iuser,
eGPUSamplerState sampler_state);
GPUSamplerState sampler_state);
void GPU_image_tiled(GPUMaterial *mat,
struct Image *ima,
struct ImageUser *iuser,
eGPUSamplerState sampler_state,
GPUSamplerState sampler_state,
GPUNodeLink **r_image_tiled_link,
GPUNodeLink **r_image_tiled_mapping_link);
GPUNodeLink *GPU_image_sky(GPUMaterial *mat,
@ -178,7 +178,7 @@ GPUNodeLink *GPU_image_sky(GPUMaterial *mat,
int height,
const float *pixels,
float *layer,
eGPUSamplerState sampler_state);
GPUSamplerState sampler_state);
GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *row);
/**
@ -355,7 +355,7 @@ typedef struct GPUMaterialTexture {
char sampler_name[32]; /* Name of sampler in GLSL. */
char tiled_mapping_name[32]; /* Name of tile mapping sampler in GLSL. */
int users;
int sampler_state; /* eGPUSamplerState */
GPUSamplerState sampler_state;
} GPUMaterialTexture;
ListBase GPU_material_attributes(GPUMaterial *material);

View File

@ -11,6 +11,11 @@
#pragma once
#ifdef __cplusplus
# include <string>
#endif
#include "BLI_assert.h"
#include "BLI_utildefines.h"
#include "GPU_state.h"
@ -22,84 +27,385 @@ extern "C" {
#endif
/* -------------------------------------------------------------------- */
/** \name Enums
/** \name Sampler State
* \{ */
/**
* A `eGPUSamplerState` specify the sampler state to bind a texture with.
* One is stored inside `GPUTexture` for default parameters.
*
* Some sampler states commonly set:
* - BORDER_COLOR is set to {0, 0, 0, 0}.
* - MIN_LOD is set to -1000.
* - MAX_LOD is set to 1000.
* - LOD_BIAS is set to 0.0.
* The `GPUSamplerFiltering` bit flag specifies the enabled filtering options of a texture
* sampler.
*/
/**
* TODO(fclem): this enum needs to be split into multiple states. One for filtering. One for
* extension / wrap mode etc...
*/
typedef enum eGPUSamplerState {
typedef enum GPUSamplerFiltering {
OmarEmaraDev marked this conversation as resolved Outdated

I think it is a good opportunity to remove the e prefix which is not part of the code-style anymore (because it doesn't add more information).

I think it is a good opportunity to remove the `e` prefix which is not part of the code-style anymore (because it doesn't add more information).
/**
* Default sampler state with all options off.
* It means no filtering, no mipmap, clamp to edge texel, no compare.
* Default sampler filtering with all options off.
* It means no linear filtering, no mipmapping, and no anisotropic filtering.
*/
GPU_SAMPLER_DEFAULT = 0,
GPU_SAMPLER_FILTERING_DEFAULT = 0,
/**
OmarEmaraDev marked this conversation as resolved Outdated

All these empty lines can be remove.

All these empty lines can be remove.
* Enables hardware linear filtering.
* Enables linear interpolation between MIPS if GPU_SAMPLER_MIPMAP is also set.
* Also enables linear interpolation between MIPS if GPU_SAMPLER_FILTERING_MIPMAP is set.
*/
GPU_SAMPLER_FILTER = (1 << 0),
GPU_SAMPLER_FILTERING_LINEAR = (1 << 0),
/**
* Enables mipmap access through shader samplers.
* Enables linear interpolation between mips if GPU_SAMPLER_FILTER is also set, otherwise the mip
* Also enables linear interpolation between mips if GPU_SAMPLER_FILTER is set, otherwise the mip
* interpolation will be set to nearest.
*
* The following parameters are always left to their default values and can't be changed:
* - TEXTURE_MIN_LOD is -1000.
* - TEXTURE_MAX_LOD is 1000.
* - TEXTURE_LOD_BIAS is 0.0f.
*/
GPU_SAMPLER_MIPMAP = (1 << 1),
GPU_SAMPLER_FILTERING_MIPMAP = (1 << 1),
/**
* Sets texture coordinate extension to repeat in X, Y and Z direction.
* If not set for some direction, either clamp to edge (texel) or border color (0,0,0,0) if
* `GPU_SAMPLER_CLAMP_BORDER` is set.
* If `GPU_SAMPLER_MIRROR_REPEAT` is set, any direction using `GPU_SAMPLER_REPEAT_*` will use a
* mirrored repeat coordinate extension.
*/
GPU_SAMPLER_REPEAT_S = (1 << 2),
GPU_SAMPLER_REPEAT_T = (1 << 3),
GPU_SAMPLER_REPEAT_R = (1 << 4),
GPU_SAMPLER_REPEAT = (GPU_SAMPLER_REPEAT_S | GPU_SAMPLER_REPEAT_T | GPU_SAMPLER_REPEAT_R),
/**
* Clamp to border color instead of border texel.
* Used for directions not using `GPU_SAMPLER_REPEAT_*`.
*/
GPU_SAMPLER_CLAMP_BORDER = (1 << 5),
/**
* Enable compare mode for depth texture. The depth texture must then be bound to a shadow
* sampler.
*/
GPU_SAMPLER_COMPARE = (1 << 6),
/** Enable Anisotropic filtering. This only has effect if `GPU_SAMPLER_MIPMAP` is set.
* Enable Anisotropic filtering. This only has effect if `GPU_SAMPLER_FILTERING_MIPMAP` is set.
* The filtered result is implementation dependent.
* The maximum amount of samples is set
*
* The maximum amount of samples is always set to its maximum possible value and can't be
* changed, except by the user through the user preferences, see the use of U.anisotropic_filter.
*/
GPU_SAMPLER_ANISO = (1 << 7),
/** Enable mirror repeat extension mode for directions using the `GPU_SAMPLER_REPEAT_*` flag. */
GPU_SAMPLER_MIRROR_REPEAT = (1 << 8),
GPU_SAMPLER_FILTERING_ANISOTROPIC = (1 << 2),
} GPUSamplerFiltering;
/** Special icon sampler with custom LOD bias and interpolation mode. */
GPU_SAMPLER_ICON = (1 << 9),
} eGPUSamplerState;
ENUM_OPERATORS(GPUSamplerFiltering, GPU_SAMPLER_FILTERING_ANISOTROPIC)
/** The number of every possible filtering configuration. */
static const int GPU_SAMPLER_FILTERING_TYPES_COUNT = (GPU_SAMPLER_FILTERING_LINEAR |
GPU_SAMPLER_FILTERING_MIPMAP |
GPU_SAMPLER_FILTERING_ANISOTROPIC) +
1;
/**
* #GPU_SAMPLER_MAX is not a valid enum value, but only a limit.
* It also creates a bad mask for the `NOT` operator in #ENUM_OPERATORS.
* The `GPUSamplerExtendMode` specifies how the texture will be extrapolated for out-of-bound
* texture sampling.
*/
typedef enum GPUSamplerExtendMode {
OmarEmaraDev marked this conversation as resolved Outdated

Wrap is a bit misleading terminology here. So maybe GPUSamplerExtendMode?

Wrap is a bit misleading terminology here. So maybe `GPUSamplerExtendMode`?
/**
* Extrapolate by extending the edge pixels of the texture, in other words, the texture
* coordinates are clamped.
*/
GPU_SAMPLER_EXTEND_MODE_EXTEND = 0,
OmarEmaraDev marked this conversation as resolved Outdated

Comment style.

Comment style.
/** Extrapolate by repeating the texture. */
GPU_SAMPLER_EXTEND_MODE_REPEAT,
/** Extrapolate by repeating the texture with mirroring in a ping-pong fashion. */
GPU_SAMPLER_EXTEND_MODE_MIRRORED_REPEAT,
OmarEmaraDev marked this conversation as resolved Outdated

I think you can omit the actual value set after the first one. Keep = 0 but remove = 1, = 2, ...

I think you can omit the actual value set after the first one. Keep ` = 0` but remove ` = 1`, ` = 2`, ...
/**
* Extrapolate using the value of TEXTURE_BORDER_COLOR, which is always set to a transparent
* black color (0, 0, 0, 0) and can't be changed.
*/
GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER,
OmarEmaraDev marked this conversation as resolved Outdated

Rename to CLAMP_TO_BORDER instead of CLIP.

Rename to `CLAMP_TO_BORDER` instead of `CLIP`.
} GPUSamplerExtendMode;
#define GPU_SAMPLER_EXTEND_MODES_COUNT (GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER + 1)
/**
* The `GPUSamplerCustomType` specifies pre-defined sampler configurations with parameters that
OmarEmaraDev marked this conversation as resolved Outdated

It was discussed that these counts should be defined like this:
#define GPU_SAMPLER_WRAP_TYPES_COUNT (GPU_SAMPLER_WRAP_CLIP + 1)

This is because it allows to skip this case in switch statements and not have a compiler warning.

It was discussed that these counts should be defined like this: `#define GPU_SAMPLER_WRAP_TYPES_COUNT (GPU_SAMPLER_WRAP_CLIP + 1)` This is because it allows to skip this case in `switch` statements and not have a compiler warning.
* are not controllable using the GPUSamplerFiltering and GPUSamplerExtendMode options. Hence, the
* use of a custom sampler type is mutually exclusive with the use of the aforementioned enums.
*
* The parameters that needs to be set for those custom samplers are not added as yet another
* option inside the GPUSamplerState structure because every possible configuration of sampler
* states are generated, setup, and cached at startup, so adding yet another axis of variation will
* multiply the number of configurations that needs to be cached, which is not worth it due to the
* limited use of the parameters needed to setup those custom samplers.
*/
typedef enum GPUSamplerCustomType {
/**
* Enable compare mode for depth texture. The depth texture must then be bound to a shadow
* sampler. This is equivalent to:
*
* - GPU_SAMPLER_FILTERING_LINEAR.
* - GPU_SAMPLER_EXTEND_MODE_EXTEND.
*
* And sets:
*
* - TEXTURE_COMPARE_MODE -> COMPARE_REF_TO_TEXTURE.
* - TEXTURE_COMPARE_FUNC -> LEQUAL.
*/
GPU_SAMPLER_CUSTOM_COMPARE = 0,
/**
* Special icon sampler with custom LOD bias and interpolation mode. This sets:
*
* - TEXTURE_MAG_FILTER -> LINEAR.
* - TEXTURE_MIN_FILTER -> LINEAR_MIPMAP_NEAREST.
* - TEXTURE_LOD_BIAS -> -0.5.
*/
GPU_SAMPLER_CUSTOM_ICON,
} GPUSamplerCustomType;
#define GPU_SAMPLER_CUSTOM_TYPES_COUNT (GPU_SAMPLER_CUSTOM_ICON + 1)
/**
* The `GPUSamplerStateType` specifies how the GPUSamplerState structure should be interpreted
* when passed around due to it being an overloaded type, see the documentation of each of the
* types for more information.
*/
typedef enum GPUSamplerStateType {
/**
* The filtering, extend_x, and extend_yz members of the GPUSamplerState structure will be used
* in setting up the sampler state for the texture. The custom_type member will be ignored in
* that case.
*/
GPU_SAMPLER_STATE_TYPE_PARAMETERS = 0,
/**
* The filtering, extend_x, and extend_yz members of the GPUSamplerState structure will be
* ignored, and the predefined custom parameters outlined in the documentation of
* GPUSamplerCustomType will be used in setting up the sampler state for the texture.
*/
GPU_SAMPLER_STATE_TYPE_CUSTOM,
/**
* The members of the GPUSamplerState structure will be ignored and the internal sampler state of
* the texture will be used. In other words, this is a signal value and stores no useful or
* actual data.
*/
GPU_SAMPLER_STATE_TYPE_INTERNAL,
OmarEmaraDev marked this conversation as resolved Outdated

Remaining value.

Remaining value.
} GPUSamplerStateType;
/**
* The `GPUSamplerState` specifies the sampler state to bind a texture with.
*
* When the state type is set to GPU_SAMPLER_STATE_TYPE_CUSTOM or GPU_SAMPLER_STATE_TYPE_INTERNAL,
* the rest of the members of the structure will be ignored. However, we can't turn this structure
* into a union, because various functions merely temporally change the state type and expect the
* rest of the members' values to be retained when the state type is changed back to
* GPU_SAMPLER_STATE_TYPE_PARAMETERS. For the instance, a function might do the following and
* expect the original sampler state of the texture to be retained after disabling comparison mode:
*
* GPU_texture_compare_mode(texture, true);
* // Use the texture ...
* GPU_texture_compare_mode(texture, false);
*
*/
typedef struct GPUSamplerState {
/** Specifies the enabled filtering options for the sampler. */
GPUSamplerFiltering filtering : 8;
/**
fclem marked this conversation as resolved Outdated

You are missing the wrapping_z for 3D texture.
Prefer using extend_x/y/z.

You are missing the `wrapping_z` for 3D texture. Prefer using `extend_x/y/z`.

I did not add a z wrapping option for now because it had no use in the code base at the moment. So I though maybe we should add it when we really need it.

I did not add a z wrapping option for now because it had no use in the code base at the moment. So I though maybe we should add it when we really need it.

The thing is, we already use 3D textures, and some of them use CLAMP_TO_BORDER (ex: Volumes Attributes) and some use EXTEND (ex: EEVEE Volume temp textures). If the choice to omit wrapping_z is to save a dimension, it should be documented. Maybe rename wrapping_y to wrapping_yz in this case and make Z follow Y extend mode.

The thing is, we already use 3D textures, and some of them use `CLAMP_TO_BORDER` (ex: Volumes Attributes) and some use `EXTEND` (ex: EEVEE Volume temp textures). If the choice to omit `wrapping_z` is to save a dimension, it should be documented. Maybe rename `wrapping_y` to `wrapping_yz` in this case and make Z follow Y extend mode.
* Specifies how the texture will be extrapolated for out-of-bound texture sampling along the x
* axis.
*/
GPUSamplerExtendMode extend_x : 4;
OmarEmaraDev marked this conversation as resolved Outdated

These should be documented. For example, I'm not sure what an internal_sampler is right away.

These should be documented. For example, I'm not sure what an `internal_sampler` is right away.
/**
* Specifies how the texture will be extrapolated for out-of-bound texture sampling along both
* the y and z axis. There is no individual control for the z axis because 3D textures have
* limited use, and when used, their extend mode is typically the same for all axis.
*/
GPUSamplerExtendMode extend_yz : 4;
/** Specifies the type of sampler if the state type is GPU_SAMPLER_STATE_TYPE_CUSTOM. */
GPUSamplerCustomType custom_type : 8;
/** Specifies how the GPUSamplerState structure should be interpreted when passed around. */
GPUSamplerStateType type : 8;
#ifdef __cplusplus
static constexpr eGPUSamplerState GPU_SAMPLER_MAX = eGPUSamplerState(GPU_SAMPLER_ICON + 1);
#else
static const int GPU_SAMPLER_MAX = (GPU_SAMPLER_ICON + 1);
/**
* Constructs a sampler state with default filtering and extended extend in both x and y axis.
* See the documentation on GPU_SAMPLER_FILTERING_DEFAULT and GPU_SAMPLER_EXTEND_MODE_EXTEND for
* more information.
*
* GPU_SAMPLER_STATE_TYPE_PARAMETERS is set in order to utilize the aforementioned parameters, so
* GPU_SAMPLER_CUSTOM_COMPARE is arbitrary, ignored, and irrelevant.
*/
static constexpr GPUSamplerState default_sampler()
{
return {GPU_SAMPLER_FILTERING_DEFAULT,
GPU_SAMPLER_EXTEND_MODE_EXTEND,
GPU_SAMPLER_EXTEND_MODE_EXTEND,
GPU_SAMPLER_CUSTOM_COMPARE,
GPU_SAMPLER_STATE_TYPE_PARAMETERS};
}
/**
* Constructs a sampler state that can be used to signal that the internal sampler of the texture
* should be used instead. See the documentation on GPU_SAMPLER_STATE_TYPE_INTERNAL for more
* information.
*
* GPU_SAMPLER_STATE_TYPE_INTERNAL is set in order to signal the use of the internal sampler of
* the texture, so the rest of the options before it are arbitrary, ignored, and irrelevant.
*/
static constexpr GPUSamplerState internal_sampler()
{
return {GPU_SAMPLER_FILTERING_DEFAULT,
OmarEmaraDev marked this conversation as resolved Outdated

I think name of the function is confusing.

To me, you should remove the condition and have an unset_filtering equivalent.
But this does make the callers use if statements most of the time.

Another possibility is to use a more descriptive name like set_filtering_flag_from_test.

I think name of the function is confusing. To me, you should remove the condition and have an `unset_filtering` equivalent. But this does make the callers use if statements most of the time. Another possibility is to use a more descriptive name like `set_filtering_flag_from_test`.

I tried couple of names and signatures for this function and eventually went for set_filtering because it apparently hides the underlying data and makes sense when reading it, for instance:

set_filtering(GPU_SAMPLER_FILTERING_MIPMAP, true);
Set mipmap filtering to true.

set_filtering(GPU_SAMPLER_FILTERING_MIPMAP, false);
Set mipmap filtering to false.

The user does not know how filtering is stored internally, the function just promises that it can be enabled or disabled, and reading the function feels natural. What do you think?

I tried couple of names and signatures for this function and eventually went for set_filtering because it apparently hides the underlying data and makes sense when reading it, for instance: ``` set_filtering(GPU_SAMPLER_FILTERING_MIPMAP, true); Set mipmap filtering to true. set_filtering(GPU_SAMPLER_FILTERING_MIPMAP, false); Set mipmap filtering to false. ``` The user does not know how filtering is stored internally, the function just promises that it can be enabled or disabled, and reading the function feels natural. What do you think?

The thing is, filtering is too generic of a name. I don't know if this will set the whole enum value or just one option if I see set_filtering(GPU_SAMPLER_FILTERING_MIPMAP). And I don't immediatly know what
false refers to when seeing set_filtering(GPU_SAMPLER_FILTERING_MIPMAP, false).

I would say enable_filtering_flag(flag), disable_filtering_flag(flag) and set_filtering_flag_from_test(flag, test) would be better from a semantical point of view.

The thing is, filtering is too generic of a name. I don't know if this will set the whole `enum` value or just one option if I see `set_filtering(GPU_SAMPLER_FILTERING_MIPMAP)`. And I don't immediatly know what `false` refers to when seeing `set_filtering(GPU_SAMPLER_FILTERING_MIPMAP, false)`. I would say `enable_filtering_flag(flag)`, `disable_filtering_flag(flag)` and `set_filtering_flag_from_test(flag, test)` would be better from a semantical point of view.
GPU_SAMPLER_EXTEND_MODE_EXTEND,
GPU_SAMPLER_EXTEND_MODE_EXTEND,
GPU_SAMPLER_CUSTOM_COMPARE,
GPU_SAMPLER_STATE_TYPE_INTERNAL};
}
/**
* Constructs a special sampler state that can be used sampler icons. See the documentation on
* GPU_SAMPLER_CUSTOM_ICON for more information.
*
* GPU_SAMPLER_STATE_TYPE_CUSTOM is set in order to specify a custom sampler type, so the rest of
* the options before it are arbitrary, ignored, and irrelevant.
*/
static constexpr GPUSamplerState icon_sampler()
{
return {GPU_SAMPLER_FILTERING_DEFAULT,
GPU_SAMPLER_EXTEND_MODE_EXTEND,
GPU_SAMPLER_EXTEND_MODE_EXTEND,
GPU_SAMPLER_CUSTOM_ICON,
GPU_SAMPLER_STATE_TYPE_CUSTOM};
}
/**
* Constructs a special sampler state for depth comparison. See the documentation on
* GPU_SAMPLER_CUSTOM_COMPARE for more information.
*
* GPU_SAMPLER_STATE_TYPE_CUSTOM is set in order to specify a custom sampler type, so the rest of
* the options before it are ignored and irrelevant, but they are set to sensible defaults in
* case comparison mode is turned off, in which case, the sampler state will become equivalent to
* GPUSamplerState::default_sampler().
*/
static constexpr GPUSamplerState compare_sampler()
{
return {GPU_SAMPLER_FILTERING_DEFAULT,
GPU_SAMPLER_EXTEND_MODE_EXTEND,
GPU_SAMPLER_EXTEND_MODE_EXTEND,
GPU_SAMPLER_CUSTOM_COMPARE,
GPU_SAMPLER_STATE_TYPE_CUSTOM};
}
/**
* Enables the given filtering flags.
*/
void enable_filtering_flag(GPUSamplerFiltering filtering_flags)
{
this->filtering = this->filtering | filtering_flags;
}
/**
* Disables the given filtering flags.
*/
void disable_filtering_flag(GPUSamplerFiltering filtering_flags)
{
this->filtering = this->filtering & ~filtering_flags;
}
/**
* Enables the given filtering flags if the given test is true, otherwise, disables the given
* filtering flags.
*/
void set_filtering_flag_from_test(GPUSamplerFiltering filtering_flags, bool test)
{
if (test) {
this->enable_filtering_flag(filtering_flags);
}
else {
this->disable_filtering_flag(filtering_flags);
}
}
std::string to_string() const
{
if (this->type == GPU_SAMPLER_STATE_TYPE_INTERNAL) {
return "internal";
}
if (this->type == GPU_SAMPLER_STATE_TYPE_CUSTOM) {
switch (this->custom_type) {
case GPU_SAMPLER_CUSTOM_COMPARE:
return "compare";
break;
case GPU_SAMPLER_CUSTOM_ICON:
return "icon";
break;
default:
BLI_assert_unreachable();
return "";
}
}
/* The sampler state is of type PARAMETERS, so serialize the parameters. */
BLI_assert(this->type == GPU_SAMPLER_STATE_TYPE_PARAMETERS);
std::string serialized_paramaters;
if (this->filtering & GPU_SAMPLER_FILTERING_LINEAR) {
serialized_paramaters += "linear-filter_";
}
if (this->filtering & GPU_SAMPLER_FILTERING_MIPMAP) {
serialized_paramaters += "mipmap_";
}
if (this->filtering & GPU_SAMPLER_FILTERING_ANISOTROPIC) {
serialized_paramaters += "anisotropic_";
}
switch (this->extend_x) {
case GPU_SAMPLER_EXTEND_MODE_EXTEND:
serialized_paramaters += "extend-x_";
break;
case GPU_SAMPLER_EXTEND_MODE_REPEAT:
serialized_paramaters += "repeat-x_";
break;
case GPU_SAMPLER_EXTEND_MODE_MIRRORED_REPEAT:
serialized_paramaters += "mirrored-repeat-x_";
break;
case GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER:
serialized_paramaters += "clamp-to-border-x_";
break;
default:
BLI_assert_unreachable();
}
switch (this->extend_yz) {
case GPU_SAMPLER_EXTEND_MODE_EXTEND:
serialized_paramaters += "extend-y_";
break;
case GPU_SAMPLER_EXTEND_MODE_REPEAT:
serialized_paramaters += "repeat-y_";
break;
case GPU_SAMPLER_EXTEND_MODE_MIRRORED_REPEAT:
serialized_paramaters += "mirrored-repeat-y_";
break;
case GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER:
serialized_paramaters += "clamp-to-border-y_";
break;
default:
BLI_assert_unreachable();
}
switch (this->extend_yz) {
case GPU_SAMPLER_EXTEND_MODE_EXTEND:
serialized_paramaters += "extend-z";
break;
case GPU_SAMPLER_EXTEND_MODE_REPEAT:
serialized_paramaters += "repeat-z";
break;
case GPU_SAMPLER_EXTEND_MODE_MIRRORED_REPEAT:
serialized_paramaters += "mirrored-repeat-z";
break;
case GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER:
serialized_paramaters += "clamp-to-border-z";
break;
default:
BLI_assert_unreachable();
}
return serialized_paramaters;
}
bool operator==(GPUSamplerState const &rhs) const
{
return this->filtering == rhs.filtering && this->extend_x == rhs.extend_x &&
this->extend_yz == rhs.extend_yz && this->custom_type == rhs.custom_type &&
this->type == rhs.type;
}
#endif
} GPUSamplerState;
#ifndef __cplusplus
/** Identical to GPUSamplerState::default_sampler for non C++ users. */
const static GPUSamplerState GPU_SAMPLER_DEFAULT = {GPU_SAMPLER_FILTERING_DEFAULT,
GPU_SAMPLER_EXTEND_MODE_EXTEND,
GPU_SAMPLER_EXTEND_MODE_EXTEND,
GPU_SAMPLER_CUSTOM_COMPARE,
GPU_SAMPLER_STATE_TYPE_PARAMETERS};
#endif
ENUM_OPERATORS(eGPUSamplerState, GPU_SAMPLER_ICON)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Enums
* \{ */
/**
* Types of texture internal storage. Defines how the data is stored inside the video memory.
@ -505,7 +811,7 @@ void GPU_texture_bind(GPUTexture *texture, int unit);
/**
* Bind a texture to a texture sampling image units using the explicit sampler state.
*/
void GPU_texture_bind_ex(GPUTexture *texture, eGPUSamplerState state, int unit);
void GPU_texture_bind_ex(GPUTexture *texture, GPUSamplerState state, int unit);
/**
* Unbind \a tex from a texture sampling image unit.
* \note this isn't strictly required but it is better for debugging purpose.
@ -538,12 +844,6 @@ void GPU_texture_image_unbind_all(void);
/** \name State API
* \{ */
/**
* Set anisotropic filter usage. Filter sample count is determined globally by
* `U.anisotropic_filter` and updated when `GPU_samplers_update` is called.
*/
void GPU_texture_anisotropic_filter(GPUTexture *texture, bool use_aniso);
/**
* Set \a tex texture depth comparison mode. Only works on depth format.
*/
@ -567,15 +867,28 @@ void GPU_texture_filter_mode(GPUTexture *texture, bool use_filter);
void GPU_texture_mipmap_mode(GPUTexture *texture, bool use_mipmap, bool use_filter);
/**
* Set \a tex texture sampling method for coordinates outside of the [0..1] uv range.
*
* If \a use_repeat is true, sampling the texture outside of the [0..1] uv range will repeat to
* border color instead of the border texel value.
*
* If \a use_clamp is true, sampling the texture outside of the [0..1] uv range will clamp to the
* closest border texel value. If set to false, it will use the values (0, 0, 0, 0) instead.
* Set anisotropic filter usage. Filter sample count is determined globally by
* `U.anisotropic_filter` and updated when `GPU_samplers_update` is called.
*/
void GPU_texture_wrap_mode(GPUTexture *texture, bool use_repeat, bool use_clamp);
void GPU_texture_anisotropic_filter(GPUTexture *texture, bool use_aniso);
/**
* Set \a tex texture sampling method for coordinates outside of the [0..1] uv range along the x
* axis. See GPUSamplerExtendMode for the available and meaning of different extend modes.
*/
void GPU_texture_extend_mode_x(GPUTexture *texture, GPUSamplerExtendMode extend_mode);
/**
* Set \a tex texture sampling method for coordinates outside of the [0..1] uv range along the y
* axis. See GPUSamplerExtendMode for the available and meaning of different extend modes.
*/
void GPU_texture_extend_mode_y(GPUTexture *texture, GPUSamplerExtendMode extend_mode);
/**
* Set \a tex texture sampling method for coordinates outside of the [0..1] uv range along both the
* x and y axis. See GPUSamplerExtendMode for the available and meaning of different extend modes.
*/
void GPU_texture_extend_mode(GPUTexture *texture, GPUSamplerExtendMode extend_mode);
/**
* Set \a tex texture swizzle state for swizzling sample components.

View File

@ -606,7 +606,7 @@ void immBindTexture(const char *name, GPUTexture *tex)
GPU_texture_bind(tex, binding);
}
void immBindTextureSampler(const char *name, GPUTexture *tex, eGPUSamplerState state)
void immBindTextureSampler(const char *name, GPUTexture *tex, GPUSamplerState state)
{
int binding = GPU_shader_get_sampler_binding(imm->shader, name);
GPU_texture_bind_ex(tex, state, binding);

View File

@ -477,7 +477,7 @@ static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph,
struct GPUTexture **colorband,
struct GPUTexture **sky,
bool is_tiled,
eGPUSamplerState sampler_state)
GPUSamplerState sampler_state)
{
/* Find existing texture. */
int num_textures = 0;
@ -625,7 +625,7 @@ GPUNodeLink *GPU_differentiate_float_function(const char *function_name)
GPUNodeLink *GPU_image(GPUMaterial *mat,
Image *ima,
ImageUser *iuser,
eGPUSamplerState sampler_state)
GPUSamplerState sampler_state)
{
GPUNodeGraph *graph = gpu_material_node_graph(mat);
GPUNodeLink *link = gpu_node_link_create();
@ -640,7 +640,7 @@ GPUNodeLink *GPU_image_sky(GPUMaterial *mat,
int height,
const float *pixels,
float *layer,
eGPUSamplerState sampler_state)
GPUSamplerState sampler_state)
{
struct GPUTexture **sky = gpu_material_sky_texture_layer_set(mat, width, height, pixels, layer);
@ -655,7 +655,7 @@ GPUNodeLink *GPU_image_sky(GPUMaterial *mat,
void GPU_image_tiled(GPUMaterial *mat,
struct Image *ima,
struct ImageUser *iuser,
eGPUSamplerState sampler_state,
GPUSamplerState sampler_state,
GPUNodeLink **r_image_tiled_link,
GPUNodeLink **r_image_tiled_mapping_link)
{
@ -681,7 +681,7 @@ GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *ro
GPUNodeLink *link = gpu_node_link_create();
link->link_type = GPU_NODE_LINK_COLORBAND;
link->texture = gpu_node_graph_add_texture(
graph, nullptr, nullptr, colorband, nullptr, false, GPU_SAMPLER_MAX);
graph, nullptr, nullptr, colorband, nullptr, false, GPUSamplerState::internal_sampler());
return link;
}

View File

@ -444,7 +444,7 @@ struct ShaderCreateInfo {
struct Sampler {
ImageType type;
eGPUSamplerState sampler;
GPUSamplerState sampler;
StringRefNull name;
};
@ -689,7 +689,7 @@ struct ShaderCreateInfo {
ImageType type,
StringRefNull name,
Frequency freq = Frequency::PASS,
eGPUSamplerState sampler = (eGPUSamplerState)-1)
GPUSamplerState sampler = GPUSamplerState::internal_sampler())
{
Resource res(Resource::BindType::SAMPLER, slot);
res.sampler.type = type;

View File

@ -149,7 +149,7 @@ class StateManager {
virtual void issue_barrier(eGPUBarrier barrier_bits) = 0;
virtual void texture_bind(Texture *tex, eGPUSamplerState sampler, int unit) = 0;
virtual void texture_bind(Texture *tex, GPUSamplerState sampler, int unit) = 0;
virtual void texture_unbind(Texture *tex) = 0;
virtual void texture_unbind_all() = 0;

View File

@ -64,7 +64,7 @@ bool Texture::init_1D(int w, int layers, int mip_len, eGPUTextureFormat format)
format_flag_ = to_format_flag(format);
type_ = (layers > 0) ? GPU_TEXTURE_1D_ARRAY : GPU_TEXTURE_1D;
if ((format_flag_ & (GPU_FORMAT_DEPTH_STENCIL | GPU_FORMAT_INTEGER)) == 0) {
sampler_state = GPU_SAMPLER_FILTER;
sampler_state.filtering = GPU_SAMPLER_FILTERING_LINEAR;
}
return this->init_internal();
}
@ -80,7 +80,7 @@ bool Texture::init_2D(int w, int h, int layers, int mip_len, eGPUTextureFormat f
format_flag_ = to_format_flag(format);
type_ = (layers > 0) ? GPU_TEXTURE_2D_ARRAY : GPU_TEXTURE_2D;
if ((format_flag_ & (GPU_FORMAT_DEPTH_STENCIL | GPU_FORMAT_INTEGER)) == 0) {
sampler_state = GPU_SAMPLER_FILTER;
sampler_state.filtering = GPU_SAMPLER_FILTERING_LINEAR;
}
return this->init_internal();
}
@ -96,7 +96,7 @@ bool Texture::init_3D(int w, int h, int d, int mip_len, eGPUTextureFormat format
format_flag_ = to_format_flag(format);
type_ = GPU_TEXTURE_3D;
if ((format_flag_ & (GPU_FORMAT_DEPTH_STENCIL | GPU_FORMAT_INTEGER)) == 0) {
sampler_state = GPU_SAMPLER_FILTER;
sampler_state.filtering = GPU_SAMPLER_FILTERING_LINEAR;
}
return this->init_internal();
}
@ -112,7 +112,7 @@ bool Texture::init_cubemap(int w, int layers, int mip_len, eGPUTextureFormat for
format_flag_ = to_format_flag(format);
type_ = (layers > 0) ? GPU_TEXTURE_CUBE_ARRAY : GPU_TEXTURE_CUBE;
if ((format_flag_ & (GPU_FORMAT_DEPTH_STENCIL | GPU_FORMAT_INTEGER)) == 0) {
sampler_state = GPU_SAMPLER_FILTER;
sampler_state.filtering = GPU_SAMPLER_FILTERING_LINEAR;
}
return this->init_internal();
}
@ -548,10 +548,10 @@ void GPU_unpack_row_length_set(uint len)
/* ------ Binding ------ */
void GPU_texture_bind_ex(GPUTexture *tex_, eGPUSamplerState state, int unit)
void GPU_texture_bind_ex(GPUTexture *tex_, GPUSamplerState state, int unit)
{
Texture *tex = reinterpret_cast<Texture *>(tex_);
state = (state >= GPU_SAMPLER_MAX) ? tex->sampler_state : state;
state = (state.type == GPU_SAMPLER_STATE_TYPE_INTERNAL) ? tex->sampler_state : state;
Context::get()->state_manager->texture_bind(tex, state, unit);
}
@ -604,7 +604,10 @@ void GPU_texture_compare_mode(GPUTexture *tex_, bool use_compare)
Texture *tex = reinterpret_cast<Texture *>(tex_);
/* Only depth formats does support compare mode. */
BLI_assert(!(use_compare) || (tex->format_flag_get() & GPU_FORMAT_DEPTH));
SET_FLAG_FROM_TEST(tex->sampler_state, use_compare, GPU_SAMPLER_COMPARE);
tex->sampler_state.type = use_compare ? GPU_SAMPLER_STATE_TYPE_CUSTOM :
GPU_SAMPLER_STATE_TYPE_PARAMETERS;
tex->sampler_state.custom_type = GPU_SAMPLER_CUSTOM_COMPARE;
}
void GPU_texture_filter_mode(GPUTexture *tex_, bool use_filter)
@ -613,7 +616,7 @@ void GPU_texture_filter_mode(GPUTexture *tex_, bool use_filter)
/* Stencil and integer format does not support filtering. */
BLI_assert(!(use_filter) ||
!(tex->format_flag_get() & (GPU_FORMAT_STENCIL | GPU_FORMAT_INTEGER)));
SET_FLAG_FROM_TEST(tex->sampler_state, use_filter, GPU_SAMPLER_FILTER);
tex->sampler_state.set_filtering_flag_from_test(GPU_SAMPLER_FILTERING_LINEAR, use_filter);
}
void GPU_texture_mipmap_mode(GPUTexture *tex_, bool use_mipmap, bool use_filter)
@ -622,8 +625,8 @@ void GPU_texture_mipmap_mode(GPUTexture *tex_, bool use_mipmap, bool use_filter)
/* Stencil and integer format does not support filtering. */
BLI_assert(!(use_filter || use_mipmap) ||
!(tex->format_flag_get() & (GPU_FORMAT_STENCIL | GPU_FORMAT_INTEGER)));
SET_FLAG_FROM_TEST(tex->sampler_state, use_mipmap, GPU_SAMPLER_MIPMAP);
SET_FLAG_FROM_TEST(tex->sampler_state, use_filter, GPU_SAMPLER_FILTER);
tex->sampler_state.set_filtering_flag_from_test(GPU_SAMPLER_FILTERING_MIPMAP, use_mipmap);
tex->sampler_state.set_filtering_flag_from_test(GPU_SAMPLER_FILTERING_LINEAR, use_filter);
}
void GPU_texture_anisotropic_filter(GPUTexture *tex_, bool use_aniso)
@ -632,14 +635,26 @@ void GPU_texture_anisotropic_filter(GPUTexture *tex_, bool use_aniso)
/* Stencil and integer format does not support filtering. */
BLI_assert(!(use_aniso) ||
!(tex->format_flag_get() & (GPU_FORMAT_STENCIL | GPU_FORMAT_INTEGER)));
SET_FLAG_FROM_TEST(tex->sampler_state, use_aniso, GPU_SAMPLER_ANISO);
tex->sampler_state.set_filtering_flag_from_test(GPU_SAMPLER_FILTERING_ANISOTROPIC, use_aniso);
}
void GPU_texture_wrap_mode(GPUTexture *tex_, bool use_repeat, bool use_clamp)
void GPU_texture_extend_mode_x(GPUTexture *tex_, GPUSamplerExtendMode extend_mode)
{
Texture *tex = reinterpret_cast<Texture *>(tex_);
SET_FLAG_FROM_TEST(tex->sampler_state, use_repeat, GPU_SAMPLER_REPEAT);
SET_FLAG_FROM_TEST(tex->sampler_state, !use_clamp, GPU_SAMPLER_CLAMP_BORDER);
tex->sampler_state.extend_x = extend_mode;
}
void GPU_texture_extend_mode_y(GPUTexture *tex_, GPUSamplerExtendMode extend_mode)
{
Texture *tex = reinterpret_cast<Texture *>(tex_);
tex->sampler_state.extend_yz = extend_mode;
}
void GPU_texture_extend_mode(GPUTexture *tex_, GPUSamplerExtendMode extend_mode)
{
Texture *tex = reinterpret_cast<Texture *>(tex_);
tex->sampler_state.extend_x = extend_mode;
tex->sampler_state.extend_yz = extend_mode;
}
void GPU_texture_swizzle_set(GPUTexture *tex, const char swizzle[4])

View File

@ -83,7 +83,7 @@ ENUM_OPERATORS(eGPUSamplerFormat, GPU_SAMPLER_TYPE_UINT)
class Texture {
public:
/** Internal Sampler state. */
eGPUSamplerState sampler_state = GPU_SAMPLER_DEFAULT;
GPUSamplerState sampler_state = GPUSamplerState::default_sampler();
/** Reference counter. */
int refcount = 1;
/** Width & Height (of source data), optional. */

View File

@ -685,8 +685,12 @@ class MTLContext : public Context {
MTLContextTextureUtils texture_utils_;
/* Texture Samplers. */
/* Cache of generated #MTLSamplerState objects based on permutations of `eGPUSamplerState`. */
id<MTLSamplerState> sampler_state_cache_[GPU_SAMPLER_MAX];
/* Cache of generated #MTLSamplerState objects based on permutations of the members of
* `GPUSamplerState`. */
id<MTLSamplerState> sampler_state_cache_[GPU_SAMPLER_EXTEND_MODES_COUNT]
[GPU_SAMPLER_EXTEND_MODES_COUNT]
[GPU_SAMPLER_FILTERING_TYPES_COUNT];
id<MTLSamplerState> custom_sampler_state_cache_[GPU_SAMPLER_CUSTOM_TYPES_COUNT];
id<MTLSamplerState> default_sampler_state_ = nil;
/* When texture sampler count exceeds the resource bind limit, an
@ -771,9 +775,8 @@ class MTLContext : public Context {
void sampler_bind(MTLSamplerState, uint sampler_unit);
void texture_unbind(gpu::MTLTexture *mtl_texture);
void texture_unbind_all();
void sampler_state_cache_init();
id<MTLSamplerState> get_sampler_from_state(MTLSamplerState state);
id<MTLSamplerState> generate_sampler_from_state(MTLSamplerState state);
id<MTLSamplerState> generate_icon_sampler();
id<MTLSamplerState> get_default_sampler_state();
/* Metal Context pipeline state. */

View File

@ -223,13 +223,7 @@ MTLContext::MTLContext(void *ghost_window, void *ghost_context)
}
/* Initialize samplers. */
for (uint i = 0; i < GPU_SAMPLER_ICON; i++) {
MTLSamplerState state;
state.state = static_cast<eGPUSamplerState>(i);
sampler_state_cache_[i] = this->generate_sampler_from_state(state);
}
/* Special sampler for icons. */
sampler_state_cache_[GPU_SAMPLER_ICON] = this->generate_icon_sampler();
this->sampler_state_cache_init();
}
MTLContext::~MTLContext()
@ -278,10 +272,22 @@ MTLContext::~MTLContext()
this->free_dummy_resources();
/* Release Sampler States. */
for (int i = 0; i < GPU_SAMPLER_MAX; i++) {
if (sampler_state_cache_[i] != nil) {
[sampler_state_cache_[i] release];
sampler_state_cache_[i] = nil;
for (int extend_yz_i = 0; extend_yz_i < GPU_SAMPLER_EXTEND_MODES_COUNT; extend_yz_i++) {
for (int extend_x_i = 0; extend_x_i < GPU_SAMPLER_EXTEND_MODES_COUNT; extend_x_i++) {
for (int filtering_i = 0; filtering_i < GPU_SAMPLER_FILTERING_TYPES_COUNT; filtering_i++) {
if (sampler_state_cache_[extend_yz_i][extend_x_i][filtering_i] != nil) {
[sampler_state_cache_[extend_yz_i][extend_x_i][filtering_i] release];
sampler_state_cache_[extend_yz_i][extend_x_i][filtering_i] = nil;
}
}
}
}
/* Release Custom Sampler States. */
for (int i = 0; i < GPU_SAMPLER_CUSTOM_TYPES_COUNT; i++) {
if (custom_sampler_state_cache_[i] != nil) {
[custom_sampler_state_cache_[i] release];
custom_sampler_state_cache_[i] = nil;
}
}
@ -2021,73 +2027,118 @@ void MTLContext::texture_unbind_all()
id<MTLSamplerState> MTLContext::get_sampler_from_state(MTLSamplerState sampler_state)
{
BLI_assert((uint)sampler_state >= 0 && ((uint)sampler_state) < GPU_SAMPLER_MAX);
return sampler_state_cache_[(uint)sampler_state];
/* Internal sampler states are signal values and do not correspond to actual samplers. */
BLI_assert(sampler_state.state.type != GPU_SAMPLER_STATE_TYPE_INTERNAL);
if (sampler_state.state.type == GPU_SAMPLER_STATE_TYPE_CUSTOM) {
return custom_sampler_state_cache_[sampler_state.state.custom_type];
}
return sampler_state_cache_[sampler_state.state.extend_yz][sampler_state.state.extend_x]
[sampler_state.state.filtering];
}
id<MTLSamplerState> MTLContext::generate_sampler_from_state(MTLSamplerState sampler_state)
/** A function that maps GPUSamplerExtendMode values to their Metal enum counterparts. */
static inline MTLSamplerAddressMode to_mtl_type(GPUSamplerExtendMode wrap_mode)
{
MTLSamplerDescriptor *descriptor = [[MTLSamplerDescriptor alloc] init];
descriptor.normalizedCoordinates = true;
MTLSamplerAddressMode clamp_type = (sampler_state.state & GPU_SAMPLER_CLAMP_BORDER) ?
MTLSamplerAddressModeClampToBorderColor :
MTLSamplerAddressModeClampToEdge;
MTLSamplerAddressMode repeat_type = (sampler_state.state & GPU_SAMPLER_MIRROR_REPEAT) ?
MTLSamplerAddressModeMirrorRepeat :
MTLSamplerAddressModeRepeat;
descriptor.rAddressMode = (sampler_state.state & GPU_SAMPLER_REPEAT_R) ? repeat_type :
clamp_type;
descriptor.sAddressMode = (sampler_state.state & GPU_SAMPLER_REPEAT_S) ? repeat_type :
clamp_type;
descriptor.tAddressMode = (sampler_state.state & GPU_SAMPLER_REPEAT_T) ? repeat_type :
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];
sampler_state_cache_[(uint)sampler_state] = state;
BLI_assert(state != nil);
[descriptor autorelease];
return state;
switch (wrap_mode) {
case GPU_SAMPLER_EXTEND_MODE_EXTEND:
return MTLSamplerAddressModeClampToEdge;
case GPU_SAMPLER_EXTEND_MODE_REPEAT:
return MTLSamplerAddressModeRepeat;
case GPU_SAMPLER_EXTEND_MODE_MIRRORED_REPEAT:
return MTLSamplerAddressModeMirrorRepeat;
case GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER:
return MTLSamplerAddressModeClampToBorderColor;
default:
BLI_assert_unreachable();
return MTLSamplerAddressModeClampToEdge;
}
}
id<MTLSamplerState> MTLContext::generate_icon_sampler()
void MTLContext::sampler_state_cache_init()
{
MTLSamplerDescriptor *descriptor = [[MTLSamplerDescriptor alloc] init];
descriptor.minFilter = MTLSamplerMinMagFilterLinear;
descriptor.magFilter = MTLSamplerMinMagFilterLinear;
descriptor.mipFilter = MTLSamplerMipFilterNearest;
descriptor.lodMinClamp = 0;
descriptor.lodMaxClamp = 1;
for (int extend_yz_i = 0; extend_yz_i < GPU_SAMPLER_EXTEND_MODES_COUNT; extend_yz_i++) {
const GPUSamplerExtendMode extend_yz = static_cast<GPUSamplerExtendMode>(extend_yz_i);
const MTLSamplerAddressMode extend_t = to_mtl_type(extend_yz);
id<MTLSamplerState> icon_state = [this->device newSamplerStateWithDescriptor:descriptor];
BLI_assert(icon_state != nil);
[descriptor autorelease];
return icon_state;
for (int extend_x_i = 0; extend_x_i < GPU_SAMPLER_EXTEND_MODES_COUNT; extend_x_i++) {
const GPUSamplerExtendMode extend_x = static_cast<GPUSamplerExtendMode>(extend_x_i);
const MTLSamplerAddressMode extend_s = to_mtl_type(extend_x);
for (int filtering_i = 0; filtering_i < GPU_SAMPLER_FILTERING_TYPES_COUNT; filtering_i++) {
const GPUSamplerFiltering filtering = GPUSamplerFiltering(filtering_i);
MTLSamplerDescriptor *descriptor = [[MTLSamplerDescriptor alloc] init];
descriptor.normalizedCoordinates = true;
descriptor.sAddressMode = extend_s;
descriptor.tAddressMode = extend_t;
descriptor.rAddressMode = extend_t;
descriptor.borderColor = MTLSamplerBorderColorTransparentBlack;
descriptor.minFilter = (filtering & GPU_SAMPLER_FILTERING_LINEAR) ?
MTLSamplerMinMagFilterLinear :
MTLSamplerMinMagFilterNearest;
descriptor.magFilter = (filtering & GPU_SAMPLER_FILTERING_LINEAR) ?
MTLSamplerMinMagFilterLinear :
MTLSamplerMinMagFilterNearest;
descriptor.mipFilter = (filtering & GPU_SAMPLER_FILTERING_MIPMAP) ?
MTLSamplerMipFilterLinear :
MTLSamplerMipFilterNotMipmapped;
descriptor.lodMinClamp = -1000;
descriptor.lodMaxClamp = 1000;
float aniso_filter = max_ff(16, U.anisotropic_filter);
descriptor.maxAnisotropy = (filtering & GPU_SAMPLER_FILTERING_MIPMAP) ? aniso_filter : 1;
descriptor.compareFunction = MTLCompareFunctionAlways;
descriptor.supportArgumentBuffers = true;
id<MTLSamplerState> state = [this->device newSamplerStateWithDescriptor:descriptor];
sampler_state_cache_[extend_yz_i][extend_x_i][filtering_i] = state;
BLI_assert(state != nil);
[descriptor autorelease];
}
}
}
/* Compare sampler for depth textures. */
{
MTLSamplerDescriptor *descriptor = [[MTLSamplerDescriptor alloc] init];
descriptor.minFilter = MTLSamplerMinMagFilterLinear;
descriptor.magFilter = MTLSamplerMinMagFilterLinear;
descriptor.compareFunction = MTLCompareFunctionLessEqual;
descriptor.lodMinClamp = -1000;
descriptor.lodMaxClamp = 1000;
descriptor.supportArgumentBuffers = true;
id<MTLSamplerState> compare_state = [this->device newSamplerStateWithDescriptor:descriptor];
custom_sampler_state_cache_[GPU_SAMPLER_CUSTOM_COMPARE] = compare_state;
BLI_assert(compare_state != nil);
[descriptor autorelease];
}
/* Custom sampler for icons. The icon texture is sampled within the shader using a -0.5f LOD
* bias. */
{
MTLSamplerDescriptor *descriptor = [[MTLSamplerDescriptor alloc] init];
descriptor.minFilter = MTLSamplerMinMagFilterLinear;
descriptor.magFilter = MTLSamplerMinMagFilterLinear;
descriptor.mipFilter = MTLSamplerMipFilterNearest;
descriptor.lodMinClamp = 0;
descriptor.lodMaxClamp = 1;
id<MTLSamplerState> icon_state = [this->device newSamplerStateWithDescriptor:descriptor];
custom_sampler_state_cache_[GPU_SAMPLER_CUSTOM_ICON] = icon_state;
BLI_assert(icon_state != nil);
[descriptor autorelease];
}
}
id<MTLSamplerState> MTLContext::get_default_sampler_state()
{
if (default_sampler_state_ == nil) {
default_sampler_state_ = this->get_sampler_from_state(DEFAULT_SAMPLER_STATE);
default_sampler_state_ = this->get_sampler_from_state({GPUSamplerState::default_sampler()});
}
return default_sampler_state_;
}
@ -2231,4 +2282,4 @@ void present(MTLRenderPassDescriptor *blit_descriptor,
/** \} */
} // blender::gpu
} // namespace blender::gpu

View File

@ -43,7 +43,7 @@ class MTLStateManager : public StateManager {
void issue_barrier(eGPUBarrier barrier_bits) override;
void texture_bind(Texture *tex, eGPUSamplerState sampler, int unit) override;
void texture_bind(Texture *tex, GPUSamplerState sampler, int unit) override;
void texture_unbind(Texture *tex) override;
void texture_unbind_all() override;

View File

@ -629,7 +629,7 @@ void MTLStateManager::texture_unpack_row_length_set(uint len)
ctx->pipeline_state.unpack_row_length = len;
}
void MTLStateManager::texture_bind(Texture *tex_, eGPUSamplerState sampler_type, int unit)
void MTLStateManager::texture_bind(Texture *tex_, GPUSamplerState sampler_type, int unit)
{
BLI_assert(tex_);
gpu::MTLTexture *mtl_tex = static_cast<gpu::MTLTexture *>(tex_);
@ -674,7 +674,7 @@ void MTLStateManager::texture_unbind_all()
void MTLStateManager::image_bind(Texture *tex_, int unit)
{
this->texture_bind(tex_, GPU_SAMPLER_DEFAULT, unit);
this->texture_bind(tex_, GPUSamplerState::default_sampler(), unit);
}
void MTLStateManager::image_unbind(Texture *tex_)
@ -689,4 +689,4 @@ void MTLStateManager::image_unbind_all()
/** \} */
} // blender::gpu
} // namespace blender::gpu

View File

@ -126,7 +126,7 @@ static const int MTL_MAX_FBO_ATTACHED = 16;
/* Samplers */
struct MTLSamplerState {
eGPUSamplerState state;
GPUSamplerState state;
/* Mip min and mip max on sampler state always the same.
* Level range now controlled with textureView to be consistent with GL baseLevel. */
@ -138,16 +138,28 @@ struct MTLSamplerState {
operator uint() const
{
return uint(state);
uint integer_representation = 0;
integer_representation |= this->state.filtering;
integer_representation |= this->state.extend_x << 8;
integer_representation |= this->state.extend_yz << 12;
integer_representation |= this->state.custom_type << 16;
integer_representation |= this->state.type << 24;
return integer_representation;
}
operator uint64_t() const
{
return uint64_t(state);
uint64_t integer_representation = 0;
integer_representation |= this->state.filtering;
integer_representation |= this->state.extend_x << 8;
integer_representation |= this->state.extend_yz << 12;
integer_representation |= this->state.custom_type << 16;
integer_representation |= this->state.type << 24;
return integer_representation;
}
};
const MTLSamplerState DEFAULT_SAMPLER_STATE = {GPU_SAMPLER_DEFAULT /*, 0, 9999*/};
const MTLSamplerState DEFAULT_SAMPLER_STATE = {GPUSamplerState::default_sampler() /*, 0, 9999*/};
class MTLTexture : public Texture {
friend class MTLContext;

View File

@ -586,7 +586,7 @@ void gpu::MTLTexture::update_sub_depth_2d(
GPU_TEXTURE_USAGE_ATTACHMENT,
nullptr);
GPU_texture_filter_mode(r32_tex_tmp, false);
GPU_texture_wrap_mode(r32_tex_tmp, false, true);
GPU_texture_extend_mode(r32_tex_tmp, GPU_SAMPLER_EXTEND_MODE_EXTEND);
gpu::MTLTexture *mtl_tex = static_cast<gpu::MTLTexture *>(unwrap(r32_tex_tmp));
mtl_tex->update_sub(mip, offset, extent, type, data);

View File

@ -444,7 +444,7 @@ void GLStateManager::set_blend(const eGPUBlend value)
/** \name Texture State Management
* \{ */
void GLStateManager::texture_bind(Texture *tex_, eGPUSamplerState sampler_type, int unit)
void GLStateManager::texture_bind(Texture *tex_, GPUSamplerState sampler_state, int unit)
{
BLI_assert(unit < GPU_max_textures());
GLTexture *tex = static_cast<GLTexture *>(tex_);
@ -453,12 +453,12 @@ void GLStateManager::texture_bind(Texture *tex_, eGPUSamplerState sampler_type,
}
/* Eliminate redundant binds. */
if ((textures_[unit] == tex->tex_id_) &&
(samplers_[unit] == GLTexture::samplers_[sampler_type])) {
(samplers_[unit] == GLTexture::get_sampler(sampler_state))) {
return;
}
targets_[unit] = tex->target_;
textures_[unit] = tex->tex_id_;
samplers_[unit] = GLTexture::samplers_[sampler_type];
samplers_[unit] = GLTexture::get_sampler(sampler_state);
tex->is_bound_ = true;
dirty_texture_binds_ |= 1ULL << unit;
}

View File

@ -64,7 +64,7 @@ class GLStateManager : public StateManager {
void issue_barrier(eGPUBarrier barrier_bits) override;
void texture_bind(Texture *tex, eGPUSamplerState sampler, int unit) override;
void texture_bind(Texture *tex, GPUSamplerState sampler, int unit) override;
/**
* Bind the texture to slot 0 for editing purpose. Used by legacy pipeline.
*/

View File

@ -5,6 +5,10 @@
* \ingroup gpu
*/
#include <string>
#include "BLI_assert.h"
#include "DNA_userdef_types.h"
#include "GPU_capabilities.h"
@ -537,60 +541,94 @@ struct GPUFrameBuffer *GLTexture::framebuffer_get()
/** \name Sampler objects
* \{ */
GLuint GLTexture::samplers_[GPU_SAMPLER_MAX] = {0};
/** A function that maps GPUSamplerExtendMode values to their OpenGL enum counterparts. */
static inline GLenum to_gl(GPUSamplerExtendMode extend_mode)
{
switch (extend_mode) {
case GPU_SAMPLER_EXTEND_MODE_EXTEND:
return GL_CLAMP_TO_EDGE;
OmarEmaraDev marked this conversation as resolved Outdated

Replace by GLenum to_gl(GPUSamplerExtendMode mode) inline function. See inline GLenum to_gl(eGPUDataFormat format) for example.

Doing so will produce a compiler error if any new enum value is being added.

Replace by `GLenum to_gl(GPUSamplerExtendMode mode)` inline function. See `inline GLenum to_gl(eGPUDataFormat format)` for example. Doing so will produce a compiler error if any new enum value is being added.
case GPU_SAMPLER_EXTEND_MODE_REPEAT:
return GL_REPEAT;
case GPU_SAMPLER_EXTEND_MODE_MIRRORED_REPEAT:
return GL_MIRRORED_REPEAT;
case GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER:
return GL_CLAMP_TO_BORDER;
default:
BLI_assert_unreachable();
return GL_CLAMP_TO_EDGE;
}
}
GLuint GLTexture::samplers_state_cache_[GPU_SAMPLER_EXTEND_MODES_COUNT]
[GPU_SAMPLER_EXTEND_MODES_COUNT]
[GPU_SAMPLER_FILTERING_TYPES_COUNT] = {};
GLuint GLTexture::custom_samplers_state_cache_[GPU_SAMPLER_CUSTOM_TYPES_COUNT] = {};
void GLTexture::samplers_init()
{
glGenSamplers(GPU_SAMPLER_MAX, samplers_);
for (int i = 0; i < GPU_SAMPLER_ICON; i++) {
eGPUSamplerState state = static_cast<eGPUSamplerState>(i);
GLenum clamp_type = (state & GPU_SAMPLER_CLAMP_BORDER) ? GL_CLAMP_TO_BORDER : GL_CLAMP_TO_EDGE;
GLenum repeat_type = (state & GPU_SAMPLER_MIRROR_REPEAT) ? GL_MIRRORED_REPEAT : GL_REPEAT;
GLenum wrap_s = (state & GPU_SAMPLER_REPEAT_S) ? repeat_type : clamp_type;
GLenum wrap_t = (state & GPU_SAMPLER_REPEAT_T) ? repeat_type : clamp_type;
GLenum wrap_r = (state & GPU_SAMPLER_REPEAT_R) ? repeat_type : clamp_type;
GLenum mag_filter = (state & GPU_SAMPLER_FILTER) ? GL_LINEAR : GL_NEAREST;
GLenum min_filter = (state & GPU_SAMPLER_FILTER) ?
((state & GPU_SAMPLER_MIPMAP) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR) :
((state & GPU_SAMPLER_MIPMAP) ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST);
GLenum compare_mode = (state & GPU_SAMPLER_COMPARE) ? GL_COMPARE_REF_TO_TEXTURE : GL_NONE;
glGenSamplers(samplers_state_cache_count_, &samplers_state_cache_[0][0][0]);
glSamplerParameteri(samplers_[i], GL_TEXTURE_WRAP_S, wrap_s);
glSamplerParameteri(samplers_[i], GL_TEXTURE_WRAP_T, wrap_t);
glSamplerParameteri(samplers_[i], GL_TEXTURE_WRAP_R, wrap_r);
glSamplerParameteri(samplers_[i], GL_TEXTURE_MIN_FILTER, min_filter);
glSamplerParameteri(samplers_[i], GL_TEXTURE_MAG_FILTER, mag_filter);
glSamplerParameteri(samplers_[i], GL_TEXTURE_COMPARE_MODE, compare_mode);
glSamplerParameteri(samplers_[i], GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
for (int extend_yz_i = 0; extend_yz_i < GPU_SAMPLER_EXTEND_MODES_COUNT; extend_yz_i++) {
const GPUSamplerExtendMode extend_yz = static_cast<GPUSamplerExtendMode>(extend_yz_i);
const GLenum extend_t = to_gl(extend_yz);
/** Other states are left to default:
* - GL_TEXTURE_BORDER_COLOR is {0, 0, 0, 0}.
* - GL_TEXTURE_MIN_LOD is -1000.
* - GL_TEXTURE_MAX_LOD is 1000.
* - GL_TEXTURE_LOD_BIAS is 0.0f.
*/
for (int extend_x_i = 0; extend_x_i < GPU_SAMPLER_EXTEND_MODES_COUNT; extend_x_i++) {
const GPUSamplerExtendMode extend_x = static_cast<GPUSamplerExtendMode>(extend_x_i);
const GLenum extend_s = to_gl(extend_x);
char sampler_name[128] = "\0\0";
SNPRINTF(sampler_name,
"%s%s%s%s%s%s%s%s%s%s%s",
(state == GPU_SAMPLER_DEFAULT) ? "_default" : "",
(state & GPU_SAMPLER_FILTER) ? "_filter" : "",
(state & GPU_SAMPLER_MIPMAP) ? "_mipmap" : "",
(state & GPU_SAMPLER_REPEAT) ? "_repeat-" : "",
(state & GPU_SAMPLER_REPEAT_S) ? "S" : "",
(state & GPU_SAMPLER_REPEAT_T) ? "T" : "",
(state & GPU_SAMPLER_REPEAT_R) ? "R" : "",
(state & GPU_SAMPLER_MIRROR_REPEAT) ? "-mirror" : "",
(state & GPU_SAMPLER_CLAMP_BORDER) ? "_clamp_border" : "",
(state & GPU_SAMPLER_COMPARE) ? "_compare" : "",
(state & GPU_SAMPLER_ANISO) ? "_aniso" : "");
debug::object_label(GL_SAMPLER, samplers_[i], &sampler_name[1]);
for (int filtering_i = 0; filtering_i < GPU_SAMPLER_FILTERING_TYPES_COUNT; filtering_i++) {
const GPUSamplerFiltering filtering = GPUSamplerFiltering(filtering_i);
const GLenum mag_filter = (filtering & GPU_SAMPLER_FILTERING_LINEAR) ? GL_LINEAR :
GL_NEAREST;
const GLenum linear_min_filter = (filtering & GPU_SAMPLER_FILTERING_MIPMAP) ?
GL_LINEAR_MIPMAP_LINEAR :
GL_LINEAR;
const GLenum nearest_min_filter = (filtering & GPU_SAMPLER_FILTERING_MIPMAP) ?
GL_NEAREST_MIPMAP_LINEAR :
GL_NEAREST;
const GLenum min_filter = (filtering & GPU_SAMPLER_FILTERING_LINEAR) ? linear_min_filter :
nearest_min_filter;
GLuint sampler = samplers_state_cache_[extend_yz_i][extend_x_i][filtering_i];
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_S, extend_s);
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_T, extend_t);
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_R, extend_t);
glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, min_filter);
glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, mag_filter);
/** Other states are left to default:
* - GL_TEXTURE_BORDER_COLOR is {0, 0, 0, 0}.
* - GL_TEXTURE_MIN_LOD is -1000.
* - GL_TEXTURE_MAX_LOD is 1000.
* - GL_TEXTURE_LOD_BIAS is 0.0f.
*/
const GPUSamplerState sampler_state = {filtering, extend_x, extend_yz};
const std::string sampler_name = sampler_state.to_string();
debug::object_label(GL_SAMPLER, sampler, sampler_name.c_str());
}
}
}
samplers_update();
/* Custom sampler for icons.
* NOTE: The icon texture is sampled within the shader using a -0.5f LOD bias. */
GLuint icon_sampler = samplers_[GPU_SAMPLER_ICON];
glGenSamplers(GPU_SAMPLER_CUSTOM_TYPES_COUNT, custom_samplers_state_cache_);
/* Compare sampler for depth textures. */
GLuint compare_sampler = custom_samplers_state_cache_[GPU_SAMPLER_CUSTOM_COMPARE];
glSamplerParameteri(compare_sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glSamplerParameteri(compare_sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glSamplerParameteri(compare_sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glSamplerParameteri(compare_sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glSamplerParameteri(compare_sampler, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glSamplerParameteri(compare_sampler, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glSamplerParameteri(compare_sampler, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
debug::object_label(GL_SAMPLER, compare_sampler, "compare");
/* Custom sampler for icons. The icon texture is sampled within the shader using a -0.5f LOD
* bias. */
GLuint icon_sampler = custom_samplers_state_cache_[GPU_SAMPLER_CUSTOM_ICON];
glSamplerParameteri(icon_sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glSamplerParameteri(icon_sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@ -606,19 +644,41 @@ void GLTexture::samplers_update()
float max_anisotropy = 1.0f;
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy);
float aniso_filter = min_ff(max_anisotropy, U.anisotropic_filter);
const float anisotropic_filter = min_ff(max_anisotropy, U.anisotropic_filter);
for (int i = 0; i < GPU_SAMPLER_ICON; i++) {
eGPUSamplerState state = static_cast<eGPUSamplerState>(i);
if ((state & GPU_SAMPLER_ANISO) && (state & GPU_SAMPLER_MIPMAP)) {
glSamplerParameterf(samplers_[i], GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso_filter);
for (int extend_yz_i = 0; extend_yz_i < GPU_SAMPLER_EXTEND_MODES_COUNT; extend_yz_i++) {
for (int extend_x_i = 0; extend_x_i < GPU_SAMPLER_EXTEND_MODES_COUNT; extend_x_i++) {
for (int filtering_i = 0; filtering_i < GPU_SAMPLER_FILTERING_TYPES_COUNT; filtering_i++) {
const GPUSamplerFiltering filtering = GPUSamplerFiltering(filtering_i);
if ((filtering & GPU_SAMPLER_FILTERING_ANISOTROPIC) &&
(filtering & GPU_SAMPLER_FILTERING_MIPMAP)) {
glSamplerParameterf(samplers_state_cache_[extend_yz_i][extend_x_i][filtering_i],
GL_TEXTURE_MAX_ANISOTROPY_EXT,
anisotropic_filter);
}
}
}
}
}
void GLTexture::samplers_free()
{
glDeleteSamplers(GPU_SAMPLER_MAX, samplers_);
glDeleteSamplers(samplers_state_cache_count_, &samplers_state_cache_[0][0][0]);
glDeleteSamplers(GPU_SAMPLER_CUSTOM_TYPES_COUNT, custom_samplers_state_cache_);
}
GLuint GLTexture::get_sampler(const GPUSamplerState &sampler_state)
{
/* Internal sampler states are signal values and do not correspond to actual samplers. */
BLI_assert(sampler_state.type != GPU_SAMPLER_STATE_TYPE_INTERNAL);
if (sampler_state.type == GPU_SAMPLER_STATE_TYPE_CUSTOM) {
return custom_samplers_state_cache_[sampler_state.custom_type];
}
return samplers_state_cache_[sampler_state.extend_yz][sampler_state.extend_x]
[sampler_state.filtering];
}
/** \} */

View File

@ -23,8 +23,23 @@ class GLTexture : public Texture {
friend class GLFrameBuffer;
private:
/** All samplers states. */
static GLuint samplers_[GPU_SAMPLER_MAX];
/**
* A cache of all possible sampler configurations stored along each of the three axis of
* variation. The first and second variation axis are the wrap mode along x and y axis
* respectively, and the third variation axis is the filtering type. See the samplers_init()
* method for more information.
*/
static GLuint samplers_state_cache_[GPU_SAMPLER_EXTEND_MODES_COUNT]
[GPU_SAMPLER_EXTEND_MODES_COUNT]
[GPU_SAMPLER_FILTERING_TYPES_COUNT];
static const int samplers_state_cache_count_ = GPU_SAMPLER_EXTEND_MODES_COUNT *
GPU_SAMPLER_EXTEND_MODES_COUNT *
GPU_SAMPLER_FILTERING_TYPES_COUNT;
/**
* A cache of all custom sampler configurations described in GPUSamplerCustomType. See the
* samplers_init() method for more information.
*/
static GLuint custom_samplers_state_cache_[GPU_SAMPLER_CUSTOM_TYPES_COUNT];
/** Target to bind the texture to (#GL_TEXTURE_1D, #GL_TEXTURE_2D, etc...). */
GLenum target_ = -1;
@ -70,10 +85,32 @@ class GLTexture : public Texture {
/* TODO(fclem): Legacy. Should be removed at some point. */
uint gl_bindcode_get() const override;
/**
* Pre-generate, setup all possible samplers and cache them in the samplers_state_cache_ and
* custom_samplers_state_cache_ arrays. This is done to avoid the runtime cost associated with
* setting up a sampler at draw time.
*/
static void samplers_init();
/**
* Free the samplers cache generated in samplers_init() method.
*/
static void samplers_free();
/**
* Updates the anisotropic filter parameters of samplers that enables anisotropic filtering. This
* is not done as a one time initialization in samplers_init() method because the user might
* change the anisotropic filtering samples in the user preferences. So it is called in
* samplers_init() method as well as every time the user preferences change.
*/
static void samplers_update();
/**
* Get the handle of the OpenGL sampler that corresponds to the given sampler state.
* The sampler is retrieved from the cached samplers computed in the samplers_init() method.
*/
static GLuint get_sampler(const GPUSamplerState &sampler_state);
protected:
/** Return true on success. */
bool init_internal() override;

View File

@ -8,7 +8,7 @@
void main()
{
/* Sample texture with LOD BIAS. Used instead of custom lod bias in GPU_SAMPLER_ICON. */
/* Sample texture with LOD BIAS. Used instead of custom lod bias in GPU_SAMPLER_CUSTOM_ICON. */
fragColor = texture(image, texCoord_interp, -0.5) * finalColor;
#ifdef DO_CORNER_MASKING

View File

@ -22,7 +22,7 @@ void VKStateManager::issue_barrier(eGPUBarrier /*barrier_bits*/)
command_buffer.submit();
}
void VKStateManager::texture_bind(Texture * /*tex*/, eGPUSamplerState /*sampler*/, int /*unit*/) {}
void VKStateManager::texture_bind(Texture * /*tex*/, GPUSamplerState /*sampler*/, int /*unit*/) {}
void VKStateManager::texture_unbind(Texture * /*tex*/) {}

View File

@ -17,7 +17,7 @@ class VKStateManager : public StateManager {
void issue_barrier(eGPUBarrier barrier_bits) override;
void texture_bind(Texture *tex, eGPUSamplerState sampler, int unit) override;
void texture_bind(Texture *tex, GPUSamplerState sampler, int unit) override;
void texture_unbind(Texture *tex) override;
void texture_unbind_all() override;

View File

@ -88,7 +88,7 @@ class DirectionalBlurOperation : public NodeOperation {
input_image.bind_as_texture(shader, "input_tx");
GPU_texture_filter_mode(input_image.texture(), true);
GPU_texture_wrap_mode(input_image.texture(), false, false);
GPU_texture_extend_mode(input_image.texture(), GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER);
const Domain domain = compute_domain();
Result &output_image = get_result("Image");

View File

@ -398,7 +398,8 @@ class GlareOperation : public NodeOperation {
input_streak_result.bind_as_texture(shader, "input_streak_tx");
GPU_texture_filter_mode(input_streak_result.texture(), true);
GPU_texture_wrap_mode(input_streak_result.texture(), false, false);
GPU_texture_extend_mode(input_streak_result.texture(),
GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER);
output_streak_result.bind_as_image(shader, "output_streak_img");
@ -585,11 +586,11 @@ class GlareOperation : public NodeOperation {
small_ghost_result.bind_as_texture(shader, "small_ghost_tx");
GPU_texture_filter_mode(small_ghost_result.texture(), true);
GPU_texture_wrap_mode(small_ghost_result.texture(), false, false);
GPU_texture_extend_mode(small_ghost_result.texture(), GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER);
big_ghost_result.bind_as_texture(shader, "big_ghost_tx");
GPU_texture_filter_mode(big_ghost_result.texture(), true);
GPU_texture_wrap_mode(big_ghost_result.texture(), false, false);
GPU_texture_extend_mode(big_ghost_result.texture(), GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER);
const int2 glare_size = get_glare_size();
Result base_ghost_result = Result::Temporary(ResultType::Color, texture_pool());

View File

@ -102,7 +102,7 @@ class LensDistortionOperation : public NodeOperation {
input_image.bind_as_texture(shader, "input_tx");
GPU_texture_filter_mode(input_image.texture(), true);
GPU_texture_wrap_mode(input_image.texture(), false, false);
GPU_texture_extend_mode(input_image.texture(), GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER);
const Domain domain = compute_domain();
@ -129,7 +129,7 @@ class LensDistortionOperation : public NodeOperation {
input_image.bind_as_texture(shader, "input_tx");
GPU_texture_filter_mode(input_image.texture(), true);
GPU_texture_wrap_mode(input_image.texture(), false, false);
GPU_texture_extend_mode(input_image.texture(), GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER);
const Domain domain = compute_domain();

View File

@ -38,10 +38,12 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
bNode *node_original = node->runtime->original ? node->runtime->original : node;
NodeTexImage *tex_original = (NodeTexImage *)node_original->storage;
ImageUser *iuser = &tex_original->iuser;
eGPUSamplerState sampler = GPU_SAMPLER_REPEAT | GPU_SAMPLER_ANISO | GPU_SAMPLER_FILTER;
GPUSamplerState sampler = {GPU_SAMPLER_FILTERING_LINEAR | GPU_SAMPLER_FILTERING_ANISOTROPIC,
GPU_SAMPLER_EXTEND_MODE_REPEAT,
GPU_SAMPLER_EXTEND_MODE_REPEAT};
/* TODO(@fclem): For now assume mipmap is always enabled. */
if (true) {
sampler |= GPU_SAMPLER_MIPMAP;
sampler.enable_filtering_flag(GPU_SAMPLER_FILTERING_MIPMAP);
}
GPUNodeLink *outalpha;
@ -63,15 +65,17 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
if (tex->projection == SHD_PROJ_EQUIRECTANGULAR) {
GPU_link(mat, "node_tex_environment_equirectangular", in[0].link, &in[0].link);
/* To fix pole issue we clamp the v coordinate. */
sampler &= ~GPU_SAMPLER_REPEAT_T;
sampler.extend_yz = GPU_SAMPLER_EXTEND_MODE_EXTEND;
/* Force the highest mipmap and don't do anisotropic filtering.
* This is to fix the artifact caused by derivatives discontinuity. */
sampler &= ~(GPU_SAMPLER_MIPMAP | GPU_SAMPLER_ANISO);
sampler.disable_filtering_flag(GPU_SAMPLER_FILTERING_MIPMAP |
GPU_SAMPLER_FILTERING_ANISOTROPIC);
}
else {
GPU_link(mat, "node_tex_environment_mirror_ball", in[0].link, &in[0].link);
/* Fix pole issue. */
sampler &= ~GPU_SAMPLER_REPEAT;
sampler.extend_x = GPU_SAMPLER_EXTEND_MODE_EXTEND;
sampler.extend_yz = GPU_SAMPLER_EXTEND_MODE_EXTEND;
}
const char *gpu_fn;
@ -85,7 +89,7 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
gpu_fn = names[0];
break;
case SHD_INTERP_CLOSEST:
sampler &= ~(GPU_SAMPLER_FILTER | GPU_SAMPLER_MIPMAP);
sampler.disable_filtering_flag(GPU_SAMPLER_FILTERING_LINEAR | GPU_SAMPLER_FILTERING_MIPMAP);
gpu_fn = names[0];
break;
default:

View File

@ -52,26 +52,33 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
node_shader_gpu_tex_mapping(mat, node, in, out);
eGPUSamplerState sampler_state = GPU_SAMPLER_DEFAULT;
GPUSamplerState sampler_state = GPUSamplerState::default_sampler();
switch (tex->extension) {
case SHD_IMAGE_EXTENSION_EXTEND:
sampler_state.extend_x = GPU_SAMPLER_EXTEND_MODE_EXTEND;
sampler_state.extend_yz = GPU_SAMPLER_EXTEND_MODE_EXTEND;
break;
case SHD_IMAGE_EXTENSION_REPEAT:
sampler_state |= GPU_SAMPLER_REPEAT;
sampler_state.extend_x = GPU_SAMPLER_EXTEND_MODE_REPEAT;
sampler_state.extend_yz = GPU_SAMPLER_EXTEND_MODE_REPEAT;
break;
case SHD_IMAGE_EXTENSION_CLIP:
sampler_state |= GPU_SAMPLER_CLAMP_BORDER;
sampler_state.extend_x = GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER;
sampler_state.extend_yz = GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER;
break;
case SHD_IMAGE_EXTENSION_MIRROR:
sampler_state |= GPU_SAMPLER_REPEAT | GPU_SAMPLER_MIRROR_REPEAT;
sampler_state.extend_x = GPU_SAMPLER_EXTEND_MODE_MIRRORED_REPEAT;
sampler_state.extend_yz = GPU_SAMPLER_EXTEND_MODE_MIRRORED_REPEAT;
break;
default:
break;
}
if (tex->interpolation != SHD_INTERP_CLOSEST) {
sampler_state |= GPU_SAMPLER_ANISO | GPU_SAMPLER_FILTER;
/* TODO(fclem): For now assume mipmap is always enabled. */
sampler_state |= GPU_SAMPLER_MIPMAP;
sampler_state.filtering = GPU_SAMPLER_FILTERING_ANISOTROPIC | GPU_SAMPLER_FILTERING_LINEAR |
GPU_SAMPLER_FILTERING_MIPMAP;
}
const bool use_cubic = ELEM(tex->interpolation, SHD_INTERP_CUBIC, SHD_INTERP_SMART);
@ -105,7 +112,7 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
case SHD_PROJ_SPHERE: {
/* This projection is known to have a derivative discontinuity.
* Hide it by turning off mipmapping. */
sampler_state &= ~GPU_SAMPLER_MIPMAP;
sampler_state.disable_filtering_flag(GPU_SAMPLER_FILTERING_MIPMAP);
GPUNodeLink *gpu_image = GPU_image(mat, ima, iuser, sampler_state);
GPU_link(mat, "point_texco_remap_square", *texco, texco);
GPU_link(mat, "point_map_to_sphere", *texco, texco);
@ -115,7 +122,7 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
case SHD_PROJ_TUBE: {
/* This projection is known to have a derivative discontinuity.
* Hide it by turning off mipmapping. */
sampler_state &= ~GPU_SAMPLER_MIPMAP;
sampler_state.disable_filtering_flag(GPU_SAMPLER_FILTERING_MIPMAP);
GPUNodeLink *gpu_image = GPU_image(mat, ima, iuser, sampler_state);
GPU_link(mat, "point_texco_remap_square", *texco, texco);
GPU_link(mat, "point_map_to_tube", *texco, texco);

View File

@ -249,9 +249,10 @@ static int node_shader_gpu_tex_sky(GPUMaterial *mat,
XYZ_to_RGB xyz_to_rgb;
get_XYZ_to_RGB_for_gpu(&xyz_to_rgb);
eGPUSamplerState sampler = GPU_SAMPLER_REPEAT | GPU_SAMPLER_FILTER;
/* To fix pole issue we clamp the v coordinate. */
sampler &= ~GPU_SAMPLER_REPEAT_T;
GPUSamplerState sampler = {GPU_SAMPLER_FILTERING_LINEAR,
GPU_SAMPLER_EXTEND_MODE_REPEAT,
GPU_SAMPLER_EXTEND_MODE_EXTEND};
float layer;
GPUNodeLink *sky_texture = GPU_image_sky(
mat, GPU_SKY_WIDTH, GPU_SKY_HEIGHT, pixels.data(), &layer, sampler);