537425c1e2fdd47f6d06c668f8c2a020f1f4036e
[mesa.git] / src / gallium / drivers / r300 / r300_texture.c
1 /*
2 * Copyright 2008 Corbin Simpson <MostAwesomeDude@gmail.com>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE. */
22
23 #include "r300_texture.h"
24
25 static int minify(int i)
26 {
27 return MAX2(1, i >> 1);
28 }
29
30 static void r300_setup_miptree(struct r300_texture* tex)
31 {
32 struct pipe_texture* base = &tex->tex;
33 int stride, size, offset;
34
35 for (int i = 0; i <= base->last_level; i++) {
36 if (i > 0) {
37 base->width[i] = minify(base->width[i-1]);
38 base->height[i] = minify(base->height[i-1]);
39 base->depth[i] = minify(base->depth[i-1]);
40 }
41
42 base->nblocksx[i] = pf_get_nblocksx(&base->block, base->width[i]);
43 base->nblocksy[i] = pf_get_nblocksy(&base->block, base->width[i]);
44
45 /* Radeons enjoy things in multiples of 32. */
46 /* XXX NPOT -> 64, not 32 */
47 stride = (base->nblocksx[i] * base->block.size + 31) & ~31;
48 size = stride * base->nblocksy[i] * base->depth[i];
49
50 /* XXX 64 for NPOT */
51 tex->offset[i] = (tex->size + 31) & ~31;
52 tex->size = tex->offset[i] + size;
53 }
54 }
55
56 /* Create a new texture. */
57 static struct pipe_texture*
58 r300_texture_create(struct pipe_screen* screen,
59 const struct pipe_texture* template)
60 {
61 /* XXX struct r300_screen* r300screen = r300_screen(screen); */
62
63 struct r300_texture* tex = CALLOC_STRUCT(r300_texture);
64
65 if (!tex) {
66 return NULL;
67 }
68
69 tex->tex = *template;
70 tex->tex.refcount = 1;
71 tex->tex.screen = screen;
72
73 r300_setup_miptree(tex);
74
75 tex->buffer = screen->buffer_create(screen, 32,
76 PIPE_BUFFER_USAGE_PIXEL,
77 tex->size);
78
79 if (!tex->buffer) {
80 FREE(tex);
81 return NULL;
82 }
83
84 return (struct pipe_texture*)tex;
85 }
86
87 static void r300_texture_release(struct pipe_screen* screen,
88 struct pipe_texture** texture)
89 {
90 if (!*texture) {
91 return;
92 }
93
94 (*texture)->refcount--;
95
96 if ((*texture)->refcount <= 0) {
97 struct r300_texture* tex = (struct r300_texture*)*texture;
98
99 pipe_buffer_reference(screen, &tex->buffer, NULL);
100
101 FREE(tex);
102 }
103
104 *texture = NULL;
105 }
106
107 static struct pipe_surface* r300_get_tex_surface(struct pipe_screen* screen,
108 struct pipe_texture* texture,
109 unsigned face,
110 unsigned level,
111 unsigned zslice,
112 unsigned flags)
113 {
114 struct r300_texture* tex = (struct r300_texture*)texture;
115 struct pipe_surface* surface = CALLOC_STRUCT(pipe_surface);
116 unsigned offset;
117
118 /* XXX this is certainly dependent on tex target */
119 offset = tex->offset[level];
120
121 if (surface) {
122 surface->refcount = 1;
123 pipe_texture_reference(&surface->texture, texture);
124 pipe_buffer_reference(screen, &surface->buffer, tex->buffer);
125 surface->format = texture->format;
126 surface->width = texture->width[level];
127 surface->height = texture->height[level];
128 surface->block = texture->block;
129 surface->nblocksx = texture->nblocksx[level];
130 surface->nblocksy = texture->nblocksy[level];
131 /* XXX save the actual stride instead plz kthnxbai */
132 surface->stride =
133 (texture->nblocksx[level] * texture->block.size + 31) & ~31;
134 surface->offset = offset;
135 surface->usage = flags;
136 surface->status = PIPE_SURFACE_STATUS_DEFINED;
137 }
138
139 return surface;
140 }
141
142 static void r300_tex_surface_release(struct pipe_screen* screen,
143 struct pipe_surface** surface)
144 {
145 struct pipe_surface* s = *surface;
146
147 s->refcount--;
148
149 if (s->refcount <= 0) {
150 pipe_texture_reference(&s->texture, NULL);
151 pipe_buffer_reference(screen, &s->buffer, NULL);
152 FREE(s);
153 }
154
155 *surface = NULL;
156 }
157
158 static struct pipe_texture*
159 r300_texture_blanket(struct pipe_screen* screen,
160 const struct pipe_texture* base,
161 const unsigned* stride,
162 struct pipe_buffer* buffer)
163 {
164 struct r300_texture* tex;
165
166 if (base->target != PIPE_TEXTURE_2D ||
167 base->last_level != 0 ||
168 base->depth[0] != 1) {
169 return NULL;
170 }
171
172 tex = CALLOC_STRUCT(r300_texture);
173 if (!tex) {
174 return NULL;
175 }
176
177 tex->tex = *base;
178 tex->tex.refcount = 1;
179 tex->tex.screen = screen;
180
181 /* XXX tex->stride = *stride; */
182
183 pipe_buffer_reference(screen, &tex->buffer, buffer);
184
185 return (struct pipe_texture*)tex;
186 }
187
188 void r300_init_screen_texture_functions(struct pipe_screen* screen)
189 {
190 screen->texture_create = r300_texture_create;
191 screen->texture_release = r300_texture_release;
192 screen->get_tex_surface = r300_get_tex_surface;
193 screen->tex_surface_release = r300_tex_surface_release;
194 screen->texture_blanket = r300_texture_blanket;
195 }