X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fstate_tracker%2Fst_sampler_view.c;h=b737011d5018d8094d273e1a5974564be5e16538;hb=6569b33b6eed94aa8722287344f9f06a9390e0e5;hp=7a6993e67c791b56e9387e1197922021c1ceeb09;hpb=25723857d95e40147e59e3fda5b5fba1b41ec5a4;p=mesa.git diff --git a/src/mesa/state_tracker/st_sampler_view.c b/src/mesa/state_tracker/st_sampler_view.c index 7a6993e67c7..b737011d501 100644 --- a/src/mesa/state_tracker/st_sampler_view.c +++ b/src/mesa/state_tracker/st_sampler_view.c @@ -43,24 +43,39 @@ /** - * Try to find a matching sampler view for the given context. - * If none is found an empty slot is initialized with a - * template and returned instead. + * Set the given view as the current context's view for the texture. + * + * Overwrites any pre-existing view of the context. + * + * Takes ownership of the view (i.e., stores the view without incrementing the + * reference count). + * + * \return the view, or NULL on error. In case of error, the reference to the + * view is released. */ -static struct pipe_sampler_view ** -st_texture_get_sampler_view(struct st_context *st, - struct st_texture_object *stObj) +static struct pipe_sampler_view * +st_texture_set_sampler_view(struct st_context *st, + struct st_texture_object *stObj, + struct pipe_sampler_view *view, + bool glsl130_or_later, bool srgb_skip_decode) { - struct pipe_sampler_view **free = NULL; + struct st_sampler_views *views; + struct st_sampler_view *free = NULL; + struct st_sampler_view *sv; GLuint i; - for (i = 0; i < stObj->num_sampler_views; ++i) { - struct pipe_sampler_view **sv = &stObj->sampler_views[i]; + simple_mtx_lock(&stObj->validate_mutex); + views = stObj->sampler_views; + + for (i = 0; i < views->count; ++i) { + sv = &views->views[i]; + /* Is the array entry used ? */ - if (*sv) { + if (sv->view) { /* check if the context matches */ - if ((*sv)->context == st->pipe) { - return sv; + if (sv->view->context == st->pipe) { + pipe_sampler_view_release(st->pipe, &sv->view); + goto found; } } else { /* Found a free slot, remember that */ @@ -69,19 +84,98 @@ st_texture_get_sampler_view(struct st_context *st, } /* Couldn't find a slot for our context, create a new one */ + if (free) { + sv = free; + } else { + if (views->count >= views->max) { + /* Allocate a larger container. */ + unsigned new_max = 2 * views->max; + unsigned new_size = sizeof(*views) + new_max * sizeof(views->views[0]); + + if (new_max < views->max || + new_max > (UINT_MAX - sizeof(*views)) / sizeof(views->views[0])) { + pipe_sampler_view_release(st->pipe, &view); + goto out; + } + + struct st_sampler_views *new_views = malloc(new_size); + if (!new_views) { + pipe_sampler_view_release(st->pipe, &view); + goto out; + } + + new_views->count = views->count; + new_views->max = new_max; + memcpy(&new_views->views[0], &views->views[0], + views->count * sizeof(views->views[0])); + + /* Initialize the pipe_sampler_view pointers to zero so that we don't + * have to worry about racing against readers when incrementing + * views->count. + */ + memset(&new_views->views[views->count], 0, + (new_max - views->count) * sizeof(views->views[0])); + + /* Use memory release semantics to ensure that concurrent readers will + * get the correct contents of the new container. + * + * Also, the write should be atomic, but that's guaranteed anyway on + * all supported platforms. + */ + p_atomic_set(&stObj->sampler_views, new_views); + + /* We keep the old container around until the texture object is + * deleted, because another thread may still be reading from it. We + * double the size of the container each time, so we end up with + * at most twice the total memory allocation. + */ + views->next = stObj->sampler_views_old; + stObj->sampler_views_old = views; - if (!free) { - /* Haven't even found a free one, resize the array */ - unsigned new_size = (stObj->num_sampler_views + 1) * - sizeof(struct pipe_sampler_view *); - stObj->sampler_views = realloc(stObj->sampler_views, new_size); - free = &stObj->sampler_views[stObj->num_sampler_views++]; - *free = NULL; + views = new_views; + } + + sv = &views->views[views->count]; + + /* Since modification is guarded by the lock, only the write part of the + * increment has to be atomic, and that's already guaranteed on all + * supported platforms without using an atomic intrinsic. + */ + views->count++; } - assert(*free == NULL); +found: + assert(sv->view == NULL); + + sv->glsl130_or_later = glsl130_or_later; + sv->srgb_skip_decode = srgb_skip_decode; + sv->view = view; + +out: + simple_mtx_unlock(&stObj->validate_mutex); + return view; +} + + +/** + * Return the most-recently validated sampler view for the texture \p stObj + * in the given context, if any. + * + * Performs no additional validation. + */ +const struct st_sampler_view * +st_texture_get_current_sampler_view(const struct st_context *st, + const struct st_texture_object *stObj) +{ + const struct st_sampler_views *views = p_atomic_read(&stObj->sampler_views); - return free; + for (unsigned i = 0; i < views->count; ++i) { + const struct st_sampler_view *sv = &views->views[i]; + if (sv->view && sv->view->context == st->pipe) + return sv; + } + + return NULL; } @@ -95,14 +189,17 @@ st_texture_release_sampler_view(struct st_context *st, { GLuint i; - for (i = 0; i < stObj->num_sampler_views; ++i) { - struct pipe_sampler_view **sv = &stObj->sampler_views[i]; + simple_mtx_lock(&stObj->validate_mutex); + struct st_sampler_views *views = stObj->sampler_views; + for (i = 0; i < views->count; ++i) { + struct pipe_sampler_view **sv = &views->views[i].view; if (*sv && (*sv)->context == st->pipe) { pipe_sampler_view_reference(sv, NULL); break; } } + simple_mtx_unlock(&stObj->validate_mutex); } @@ -116,9 +213,18 @@ st_texture_release_all_sampler_views(struct st_context *st, { GLuint i; - /* XXX This should use sampler_views[i]->pipe, not st->pipe */ - for (i = 0; i < stObj->num_sampler_views; ++i) - pipe_sampler_view_release(st->pipe, &stObj->sampler_views[i]); + /* TODO: This happens while a texture is deleted, because the Driver API + * is asymmetric: the driver allocates the texture object memory, but + * mesa/main frees it. + */ + if (!stObj->sampler_views) + return; + + simple_mtx_lock(&stObj->validate_mutex); + struct st_sampler_views *views = stObj->sampler_views; + for (i = 0; i < views->count; ++i) + pipe_sampler_view_release(st->pipe, &views->views[i].view); + simple_mtx_unlock(&stObj->validate_mutex); } @@ -127,7 +233,12 @@ st_texture_free_sampler_views(struct st_texture_object *stObj) { free(stObj->sampler_views); stObj->sampler_views = NULL; - stObj->num_sampler_views = 0; + + while (stObj->sampler_views_old) { + struct st_sampler_views *views = stObj->sampler_views_old; + stObj->sampler_views_old = views->next; + free(views); + } } @@ -189,49 +300,27 @@ swizzle_swizzle(unsigned swizzle1, unsigned swizzle2) */ static unsigned compute_texture_format_swizzle(GLenum baseFormat, GLenum depthMode, - enum pipe_format actualFormat, bool glsl130_or_later) { switch (baseFormat) { case GL_RGBA: return SWIZZLE_XYZW; case GL_RGB: - if (util_format_has_alpha(actualFormat)) - return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_ONE); - else - return SWIZZLE_XYZW; + return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_ONE); case GL_RG: - if (util_format_get_nr_components(actualFormat) > 2) - return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_ZERO, SWIZZLE_ONE); - else - return SWIZZLE_XYZW; + return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_ZERO, SWIZZLE_ONE); case GL_RED: - if (util_format_get_nr_components(actualFormat) > 1) - return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_ZERO, - SWIZZLE_ZERO, SWIZZLE_ONE); - else - return SWIZZLE_XYZW; + return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_ZERO, + SWIZZLE_ZERO, SWIZZLE_ONE); case GL_ALPHA: - if (util_format_get_nr_components(actualFormat) > 1) - return MAKE_SWIZZLE4(SWIZZLE_ZERO, SWIZZLE_ZERO, - SWIZZLE_ZERO, SWIZZLE_W); - else - return SWIZZLE_XYZW; + return MAKE_SWIZZLE4(SWIZZLE_ZERO, SWIZZLE_ZERO, + SWIZZLE_ZERO, SWIZZLE_W); case GL_LUMINANCE: - if (util_format_get_nr_components(actualFormat) > 1) - return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_ONE); - else - return SWIZZLE_XYZW; + return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_ONE); case GL_LUMINANCE_ALPHA: - if (util_format_get_nr_components(actualFormat) > 2) - return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_W); - else - return SWIZZLE_XYZW; + return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_W); case GL_INTENSITY: - if (util_format_get_nr_components(actualFormat) > 1) - return SWIZZLE_XXXX; - else - return SWIZZLE_XYZW; + return SWIZZLE_XXXX; case GL_STENCIL_INDEX: case GL_DEPTH_STENCIL: case GL_DEPTH_COMPONENT: @@ -301,7 +390,6 @@ get_texture_format_swizzle(const struct st_context *st, } tex_swizzle = compute_texture_format_swizzle(baseFormat, depth_mode, - stObj->pt->format, glsl130_or_later); /* Combine the texture format swizzle with user's swizzle */ @@ -357,7 +445,7 @@ last_layer(const struct st_texture_object *stObj) static enum pipe_format get_sampler_view_format(struct st_context *st, const struct st_texture_object *stObj, - const struct gl_sampler_object *samp) + bool srgb_skip_decode) { enum pipe_format format; @@ -374,7 +462,7 @@ get_sampler_view_format(struct st_context *st, } /* If sRGB decoding is off, use the linear format */ - if (samp->sRGBDecode == GL_SKIP_DECODE_EXT) + if (srgb_skip_decode) format = util_format_linear(format); /* Use R8_UNORM for video formats */ @@ -396,14 +484,18 @@ st_create_texture_sampler_view_from_stobj(struct st_context *st, enum pipe_format format, bool glsl130_or_later) { + /* There is no need to clear this structure (consider CPU overhead). */ struct pipe_sampler_view templ; unsigned swizzle = get_texture_format_swizzle(st, stObj, glsl130_or_later); - u_sampler_view_default_template(&templ, stObj->pt, format); + templ.format = format; - templ.u.tex.first_level = stObj->base.MinLevel + stObj->base.BaseLevel; - templ.u.tex.last_level = last_level(stObj); - assert(templ.u.tex.first_level <= templ.u.tex.last_level); + if (stObj->level_override) { + templ.u.tex.first_level = templ.u.tex.last_level = stObj->level_override; + } else { + templ.u.tex.first_level = stObj->base.MinLevel + stObj->base.BaseLevel; + templ.u.tex.last_level = last_level(stObj); + } if (stObj->layer_override) { templ.u.tex.first_layer = templ.u.tex.last_layer = stObj->layer_override; } else { @@ -411,6 +503,7 @@ st_create_texture_sampler_view_from_stobj(struct st_context *st, templ.u.tex.last_layer = last_layer(stObj); } assert(templ.u.tex.first_layer <= templ.u.tex.last_layer); + assert(templ.u.tex.first_level <= templ.u.tex.last_level); templ.target = gl_target_to_pipe(stObj->base.Target); templ.swizzle_r = GET_SWZ(swizzle, 0); @@ -426,44 +519,47 @@ struct pipe_sampler_view * st_get_texture_sampler_view_from_stobj(struct st_context *st, struct st_texture_object *stObj, const struct gl_sampler_object *samp, - bool glsl130_or_later) + bool glsl130_or_later, + bool ignore_srgb_decode) { - struct pipe_sampler_view **sv; + const struct st_sampler_view *sv; + bool srgb_skip_decode = false; - if (!stObj || !stObj->pt) { - return NULL; - } + if (!ignore_srgb_decode && samp->sRGBDecode == GL_SKIP_DECODE_EXT) + srgb_skip_decode = true; - sv = st_texture_get_sampler_view(st, stObj); + sv = st_texture_get_current_sampler_view(st, stObj); - if (*sv) { + if (sv && + sv->glsl130_or_later == glsl130_or_later && + sv->srgb_skip_decode == srgb_skip_decode) { /* Debug check: make sure that the sampler view's parameters are * what they're supposed to be. */ - MAYBE_UNUSED struct pipe_sampler_view *view = *sv; + struct pipe_sampler_view *view = sv->view; assert(stObj->pt == view->texture); assert(!check_sampler_swizzle(st, stObj, view, glsl130_or_later)); - assert(get_sampler_view_format(st, stObj, samp) == view->format); + assert(get_sampler_view_format(st, stObj, srgb_skip_decode) == view->format); assert(gl_target_to_pipe(stObj->base.Target) == view->target); - assert(stObj->base.MinLevel + stObj->base.BaseLevel == - view->u.tex.first_level); - assert(last_level(stObj) == view->u.tex.last_level); + assert(stObj->level_override || + stObj->base.MinLevel + stObj->base.BaseLevel == view->u.tex.first_level); + assert(stObj->level_override || last_level(stObj) == view->u.tex.last_level); assert(stObj->layer_override || stObj->base.MinLayer == view->u.tex.first_layer); assert(stObj->layer_override || last_layer(stObj) == view->u.tex.last_layer); assert(!stObj->layer_override || (stObj->layer_override == view->u.tex.first_layer && stObj->layer_override == view->u.tex.last_layer)); + return view; } - else { - /* create new sampler view */ - enum pipe_format format = get_sampler_view_format(st, stObj, samp); - *sv = st_create_texture_sampler_view_from_stobj(st, stObj, - format, glsl130_or_later); + /* create new sampler view */ + enum pipe_format format = get_sampler_view_format(st, stObj, srgb_skip_decode); + struct pipe_sampler_view *view = + st_create_texture_sampler_view_from_stobj(st, stObj, format, glsl130_or_later); - } + view = st_texture_set_sampler_view(st, stObj, view, glsl130_or_later, srgb_skip_decode); - return *sv; + return view; } @@ -471,58 +567,65 @@ struct pipe_sampler_view * st_get_buffer_sampler_view_from_stobj(struct st_context *st, struct st_texture_object *stObj) { - struct pipe_sampler_view **sv; + const struct st_sampler_view *sv; struct st_buffer_object *stBuf = st_buffer_object(stObj->base.BufferObject); if (!stBuf || !stBuf->buffer) return NULL; - sv = st_texture_get_sampler_view(st, stObj); + sv = st_texture_get_current_sampler_view(st, stObj); struct pipe_resource *buf = stBuf->buffer; - struct pipe_sampler_view *view = *sv; - if (view && view->texture == buf) { - /* Debug check: make sure that the sampler view's parameters are - * what they're supposed to be. - */ - assert(st_mesa_format_to_pipe_format(st, stObj->base._BufferObjectFormat) + if (sv) { + struct pipe_sampler_view *view = sv->view; + + if (view->texture == buf) { + /* Debug check: make sure that the sampler view's parameters are + * what they're supposed to be. + */ + assert(st_mesa_format_to_pipe_format(st, stObj->base._BufferObjectFormat) == view->format); - assert(view->target == PIPE_BUFFER); - unsigned base = stObj->base.BufferOffset; - MAYBE_UNUSED unsigned size = MIN2(buf->width0 - base, + assert(view->target == PIPE_BUFFER); + unsigned base = stObj->base.BufferOffset; + MAYBE_UNUSED unsigned size = MIN2(buf->width0 - base, (unsigned) stObj->base.BufferSize); - assert(view->u.buf.offset == base); - assert(view->u.buf.size == size); - } else { - unsigned base = stObj->base.BufferOffset; + assert(view->u.buf.offset == base); + assert(view->u.buf.size == size); + return view; + } + } - if (base >= buf->width0) - return NULL; + unsigned base = stObj->base.BufferOffset; - unsigned size = buf->width0 - base; - size = MIN2(size, (unsigned)stObj->base.BufferSize); - if (!size) - return NULL; + if (base >= buf->width0) + return NULL; - /* Create a new sampler view. There is no need to clear the entire - * structure (consider CPU overhead). - */ - struct pipe_sampler_view templ; - - templ.format = - st_mesa_format_to_pipe_format(st, stObj->base._BufferObjectFormat); - templ.target = PIPE_BUFFER; - templ.swizzle_r = PIPE_SWIZZLE_X; - templ.swizzle_g = PIPE_SWIZZLE_Y; - templ.swizzle_b = PIPE_SWIZZLE_Z; - templ.swizzle_a = PIPE_SWIZZLE_W; - templ.u.buf.offset = base; - templ.u.buf.size = size; - - pipe_sampler_view_reference(sv, NULL); - *sv = st->pipe->create_sampler_view(st->pipe, buf, &templ); - } - return *sv; + unsigned size = buf->width0 - base; + size = MIN2(size, (unsigned)stObj->base.BufferSize); + if (!size) + return NULL; + + /* Create a new sampler view. There is no need to clear the entire + * structure (consider CPU overhead). + */ + struct pipe_sampler_view templ; + + templ.format = + st_mesa_format_to_pipe_format(st, stObj->base._BufferObjectFormat); + templ.target = PIPE_BUFFER; + templ.swizzle_r = PIPE_SWIZZLE_X; + templ.swizzle_g = PIPE_SWIZZLE_Y; + templ.swizzle_b = PIPE_SWIZZLE_Z; + templ.swizzle_a = PIPE_SWIZZLE_W; + templ.u.buf.offset = base; + templ.u.buf.size = size; + + struct pipe_sampler_view *view = + st->pipe->create_sampler_view(st->pipe, buf, &templ); + + view = st_texture_set_sampler_view(st, stObj, view, false, false); + + return view; }