diff options
Diffstat (limited to 'src/gallium/drivers/r300/r300_texture.c')
-rw-r--r-- | src/gallium/drivers/r300/r300_texture.c | 204 |
1 files changed, 159 insertions, 45 deletions
diff --git a/src/gallium/drivers/r300/r300_texture.c b/src/gallium/drivers/r300/r300_texture.c index 590052509c..aea25cf71d 100644 --- a/src/gallium/drivers/r300/r300_texture.c +++ b/src/gallium/drivers/r300/r300_texture.c @@ -20,43 +20,99 @@ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include "pipe/p_screen.h" + +#include "util/u_math.h" +#include "util/u_memory.h" + +#include "r300_context.h" #include "r300_texture.h" +#include "r300_screen.h" -static void r300_setup_texture_state(struct r300_texture* tex, - unsigned width, - unsigned height, - unsigned pitch, - unsigned levels) +static void r300_setup_texture_state(struct r300_texture* tex, boolean is_r500) { struct r300_texture_state* state = &tex->state; + struct pipe_texture *pt = &tex->tex; + + state->format0 = R300_TX_WIDTH((pt->width[0] - 1) & 0x7ff) | + R300_TX_HEIGHT((pt->height[0] - 1) & 0x7ff); + + if (tex->is_npot) { + /* rectangles love this */ + state->format0 |= R300_TX_PITCH_EN; + state->format2 = (tex->pitch[0] - 1) & 0x1fff; + } else { + /* power of two textures (3D, mipmaps, and no pitch) */ + state->format0 |= R300_TX_DEPTH(util_logbase2(pt->depth[0]) & 0xf) | + R300_TX_NUM_LEVELS(pt->last_level & 0xf); + } - state->format0 = R300_TX_WIDTH((width - 1) & 0x7ff) | - R300_TX_HEIGHT((height - 1) & 0x7ff) | - R300_TX_NUM_LEVELS(levels) | - R300_TX_PITCH_EN; + state->format1 = r300_translate_texformat(pt->format); + if (pt->target == PIPE_TEXTURE_CUBE) { + state->format1 |= R300_TX_FORMAT_CUBIC_MAP; + } + if (pt->target == PIPE_TEXTURE_3D) { + state->format1 |= R300_TX_FORMAT_3D; + } - /* XXX */ - state->format1 = r300_translate_texformat(tex->tex.format); + /* large textures on r500 */ + if (is_r500) + { + if (pt->width[0] > 2048) { + state->format2 |= R500_TXWIDTH_BIT11; + } + if (pt->height[0] > 2048) { + state->format2 |= R500_TXHEIGHT_BIT11; + } + } + assert(is_r500 || (pt->width[0] <= 2048 && pt->height[0] <= 2048)); - state->format2 = pitch - 1; + debug_printf("r300: Set texture state (%dx%d, %d levels)\n", + pt->width[0], pt->height[0], pt->last_level); +} - /* Assume (somewhat foolishly) that oversized textures will - * not be permitted by the state tracker. */ - if (width > 2048) { - state->format2 |= R500_TXWIDTH_BIT11; +unsigned r300_texture_get_offset(struct r300_texture* tex, unsigned level, + unsigned zslice, unsigned face) +{ + unsigned offset = tex->offset[level]; + + switch (tex->tex.target) { + case PIPE_TEXTURE_3D: + assert(face == 0); + return offset + zslice * tex->layer_size[level]; + + case PIPE_TEXTURE_CUBE: + assert(zslice == 0); + return offset + face * tex->layer_size[level]; + + default: + assert(zslice == 0 && face == 0); + return offset; } - if (height > 2048) { - state->format2 |= R500_TXHEIGHT_BIT11; +} + +/** + * Return the stride, in bytes, of the texture images of the given texture + * at the given level. + */ +unsigned r300_texture_get_stride(struct r300_texture* tex, unsigned level) +{ + if (tex->stride_override) + return tex->stride_override; + + if (level > tex->tex.last_level) { + debug_printf("%s: level (%u) > last_level (%u)\n", __FUNCTION__, + level, tex->tex.last_level); + return 0; } - debug_printf("r300: Set texture state (%dx%d, pitch %d, %d levels)\n", - width, height, pitch, levels); + return align(pf_get_stride(&tex->tex.block, tex->tex.width[level]), 32); } static void r300_setup_miptree(struct r300_texture* tex) { struct pipe_texture* base = &tex->tex; - int stride, size, offset; + int stride, size, layer_size; int i; for (i = 0; i <= base->last_level; i++) { @@ -69,28 +125,32 @@ static void r300_setup_miptree(struct r300_texture* tex) base->nblocksx[i] = pf_get_nblocksx(&base->block, base->width[i]); base->nblocksy[i] = pf_get_nblocksy(&base->block, base->height[i]); - /* Radeons enjoy things in multiples of 64. - * - * XXX - * POT, uncompressed, unmippmapped textures can be aligned to 32, - * instead of 64. */ - stride = align(pf_get_stride(&base->block, base->width[i]), 32); - size = stride * base->nblocksy[i] * base->depth[i]; + stride = r300_texture_get_stride(tex, i); + layer_size = stride * base->nblocksy[i]; + + if (base->target == PIPE_TEXTURE_CUBE) + size = layer_size * 6; + else + size = layer_size * base->depth[i]; tex->offset[i] = align(tex->size, 32); tex->size = tex->offset[i] + size; + tex->layer_size[i] = layer_size; + tex->pitch[i] = stride / base->block.size; debug_printf("r300: Texture miptree: Level %d " "(%dx%dx%d px, pitch %d bytes)\n", i, base->width[i], base->height[i], base->depth[i], stride); - /* Save stride of first level to the texture. */ - if (i == 0) { - tex->stride = stride; - } } } +static void r300_setup_flags(struct r300_texture* tex) +{ + tex->is_npot = !util_is_power_of_two(tex->tex.width[0]) || + !util_is_power_of_two(tex->tex.height[0]); +} + /* Create a new texture. */ static struct pipe_texture* r300_texture_create(struct pipe_screen* screen, @@ -106,10 +166,9 @@ static struct pipe_texture* pipe_reference_init(&tex->tex.reference, 1); tex->tex.screen = screen; + r300_setup_flags(tex); r300_setup_miptree(tex); - - r300_setup_texture_state(tex, template->width[0], template->height[0], - template->width[0], template->last_level); + r300_setup_texture_state(tex, r300_screen(screen)->caps->is_r500); tex->buffer = screen->buffer_create(screen, 1024, PIPE_BUFFER_USAGE_PIXEL, @@ -143,8 +202,7 @@ static struct pipe_surface* r300_get_tex_surface(struct pipe_screen* screen, struct pipe_surface* surface = CALLOC_STRUCT(pipe_surface); unsigned offset; - /* XXX this is certainly dependent on tex target */ - offset = tex->offset[level]; + offset = r300_texture_get_offset(tex, level, zslice, face); if (surface) { pipe_reference_init(&surface->reference, 1); @@ -154,6 +212,10 @@ static struct pipe_surface* r300_get_tex_surface(struct pipe_screen* screen, surface->height = texture->height[level]; surface->offset = offset; surface->usage = flags; + surface->zslice = zslice; + surface->texture = texture; + surface->face = face; + surface->level = level; } return surface; @@ -173,10 +235,10 @@ static struct pipe_texture* { struct r300_texture* tex; - /* XXX we should start doing mips now... */ + /* Support only 2D textures without mipmaps */ if (base->target != PIPE_TEXTURE_2D || - base->last_level != 0 || - base->depth[0] != 1) { + base->depth[0] != 1 || + base->last_level != 0) { return NULL; } @@ -189,17 +251,66 @@ static struct pipe_texture* pipe_reference_init(&tex->tex.reference, 1); tex->tex.screen = screen; - tex->stride = *stride; + tex->stride_override = *stride; + tex->pitch[0] = *stride / base->block.size; - /* XXX */ - r300_setup_texture_state(tex, tex->tex.width[0], tex->tex.height[0], - tex->stride, 0); + r300_setup_flags(tex); + r300_setup_texture_state(tex, r300_screen(screen)->caps->is_r500); pipe_buffer_reference(&tex->buffer, buffer); return (struct pipe_texture*)tex; } +static struct pipe_video_surface * +r300_video_surface_create(struct pipe_screen *screen, + enum pipe_video_chroma_format chroma_format, + unsigned width, unsigned height) +{ + struct r300_video_surface *r300_vsfc; + struct pipe_texture template; + + assert(screen); + assert(width && height); + + r300_vsfc = CALLOC_STRUCT(r300_video_surface); + if (!r300_vsfc) + return NULL; + + pipe_reference_init(&r300_vsfc->base.reference, 1); + r300_vsfc->base.screen = screen; + r300_vsfc->base.chroma_format = chroma_format; + r300_vsfc->base.width = width; + r300_vsfc->base.height = height; + + memset(&template, 0, sizeof(struct pipe_texture)); + template.target = PIPE_TEXTURE_2D; + template.format = PIPE_FORMAT_X8R8G8B8_UNORM; + template.last_level = 0; + template.width[0] = util_next_power_of_two(width); + template.height[0] = util_next_power_of_two(height); + template.depth[0] = 1; + pf_get_block(template.format, &template.block); + template.tex_usage = PIPE_TEXTURE_USAGE_SAMPLER | + PIPE_TEXTURE_USAGE_RENDER_TARGET; + + r300_vsfc->tex = screen->texture_create(screen, &template); + if (!r300_vsfc->tex) + { + FREE(r300_vsfc); + return NULL; + } + + return &r300_vsfc->base; +} + +static void r300_video_surface_destroy(struct pipe_video_surface *vsfc) +{ + struct r300_video_surface *r300_vsfc = r300_video_surface(vsfc); + pipe_texture_reference(&r300_vsfc->tex, NULL); + FREE(r300_vsfc); +} + void r300_init_screen_texture_functions(struct pipe_screen* screen) { screen->texture_create = r300_texture_create; @@ -207,6 +318,9 @@ void r300_init_screen_texture_functions(struct pipe_screen* screen) screen->get_tex_surface = r300_get_tex_surface; screen->tex_surface_destroy = r300_tex_surface_destroy; screen->texture_blanket = r300_texture_blanket; + + screen->video_surface_create = r300_video_surface_create; + screen->video_surface_destroy= r300_video_surface_destroy; } boolean r300_get_texture_buffer(struct pipe_texture* texture, @@ -221,7 +335,7 @@ boolean r300_get_texture_buffer(struct pipe_texture* texture, pipe_buffer_reference(buffer, tex->buffer); if (stride) { - *stride = tex->stride; + *stride = r300_texture_get_stride(tex, 0); } return TRUE; |