include surface.offset in address calculations
[mesa.git] / src / mesa / pipe / softpipe / sp_region.c
1 /**************************************************************************
2 *
3 * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 /* Provide additional functionality on top of bufmgr buffers:
29 * - 2d semantics and blit operations (XXX: remove/simplify blits??)
30 * - refcounting of buffers for multiple images in a buffer.
31 * - refcounting of buffer mappings.
32 */
33
34 #include "sp_context.h"
35 #include "sp_winsys.h"
36 #include "sp_region.h"
37
38
39 static void
40 sp_region_idle(struct pipe_context *pipe, struct pipe_region *region)
41 {
42
43 }
44
45
46 static GLubyte *
47 sp_region_map(struct pipe_context *pipe, struct pipe_region *region)
48 {
49 struct softpipe_context *sp = softpipe_context( pipe );
50
51 if (!region->map_refcount++) {
52 region->map = sp->winsys->buffer_map( sp->winsys,
53 region->buffer );
54 }
55
56 return region->map;
57 }
58
59 static void
60 sp_region_unmap(struct pipe_context *pipe, struct pipe_region *region)
61 {
62 struct softpipe_context *sp = softpipe_context( pipe );
63
64 if (!--region->map_refcount) {
65 sp->winsys->buffer_unmap( sp->winsys,
66 region->buffer );
67 region->map = NULL;
68 }
69 }
70
71 static struct pipe_region *
72 sp_region_alloc(struct pipe_context *pipe,
73 GLuint cpp, GLuint pitch, GLuint height)
74 {
75 struct softpipe_context *sp = softpipe_context( pipe );
76 struct pipe_region *region = calloc(sizeof(*region), 1);
77
78 region->cpp = cpp;
79 region->pitch = pitch;
80 region->height = height; /* needed? */
81 region->refcount = 1;
82
83 region->buffer = sp->winsys->create_buffer( sp->winsys, 64 );
84
85 sp->winsys->buffer_data( sp->winsys,
86 region->buffer,
87 pitch * cpp * height,
88 NULL );
89
90 return region;
91 }
92
93 static void
94 sp_region_release(struct pipe_context *pipe, struct pipe_region **region)
95 {
96 struct softpipe_context *sp = softpipe_context( pipe );
97
98 if (!*region)
99 return;
100
101 ASSERT((*region)->refcount > 0);
102 (*region)->refcount--;
103
104 if ((*region)->refcount == 0) {
105 assert((*region)->map_refcount == 0);
106
107 sp->winsys->buffer_unreference( sp->winsys,
108 (*region)->buffer );
109 free(*region);
110 }
111 *region = NULL;
112 }
113
114
115 /*
116 * XXX Move this into core Mesa?
117 */
118 static void
119 _mesa_copy_rect(GLubyte * dst,
120 GLuint cpp,
121 GLuint dst_pitch,
122 GLuint dst_x,
123 GLuint dst_y,
124 GLuint width,
125 GLuint height,
126 const GLubyte * src,
127 GLuint src_pitch,
128 GLuint src_x,
129 GLuint src_y)
130 {
131 GLuint i;
132
133 dst_pitch *= cpp;
134 src_pitch *= cpp;
135 dst += dst_x * cpp;
136 src += src_x * cpp;
137 dst += dst_y * dst_pitch;
138 src += src_y * dst_pitch;
139 width *= cpp;
140
141 if (width == dst_pitch && width == src_pitch)
142 memcpy(dst, src, height * width);
143 else {
144 for (i = 0; i < height; i++) {
145 memcpy(dst, src, width);
146 dst += dst_pitch;
147 src += src_pitch;
148 }
149 }
150 }
151
152
153 /* Upload data to a rectangular sub-region. Lots of choices how to do this:
154 *
155 * - memcpy by span to current destination
156 * - upload data as new buffer and blit
157 *
158 * Currently always memcpy.
159 */
160 static void
161 sp_region_data(struct pipe_context *pipe,
162 struct pipe_region *dst,
163 GLuint dst_offset,
164 GLuint dstx, GLuint dsty,
165 const void *src, GLuint src_pitch,
166 GLuint srcx, GLuint srcy, GLuint width, GLuint height)
167 {
168 _mesa_copy_rect(pipe->region_map(pipe, dst) + dst_offset,
169 dst->cpp,
170 dst->pitch,
171 dstx, dsty, width, height, src, src_pitch, srcx, srcy);
172
173 pipe->region_unmap(pipe, dst);
174 }
175
176 /* Assumes all values are within bounds -- no checking at this level -
177 * do it higher up if required.
178 */
179 static void
180 sp_region_copy(struct pipe_context *pipe,
181 struct pipe_region *dst,
182 GLuint dst_offset,
183 GLuint dstx, GLuint dsty,
184 struct pipe_region *src,
185 GLuint src_offset,
186 GLuint srcx, GLuint srcy, GLuint width, GLuint height)
187 {
188 assert( dst->cpp == src->cpp );
189
190 _mesa_copy_rect(pipe->region_map(pipe, dst) + dst_offset,
191 dst->cpp,
192 dst->pitch,
193 dstx, dsty,
194 width, height,
195 pipe->region_map(pipe, src) + src_offset,
196 src->pitch,
197 srcx, srcy);
198
199 pipe->region_unmap(pipe, src);
200 pipe->region_unmap(pipe, dst);
201 }
202
203 /* Fill a rectangular sub-region. Need better logic about when to
204 * push buffers into AGP - will currently do so whenever possible.
205 */
206 static GLubyte *
207 get_pointer(struct pipe_region *dst, GLuint x, GLuint y)
208 {
209 return dst->map + (y * dst->pitch + x) * dst->cpp;
210 }
211
212
213 static void
214 sp_region_fill(struct pipe_context *pipe,
215 struct pipe_region *dst,
216 GLuint dst_offset,
217 GLuint dstx, GLuint dsty,
218 GLuint width, GLuint height, GLuint value)
219 {
220 GLuint i, j;
221
222 (void)pipe->region_map(pipe, dst);
223
224 switch (dst->cpp) {
225 case 1: {
226 GLubyte *row = get_pointer(dst, dstx, dsty);
227 for (i = 0; i < height; i++) {
228 memset(row, value, width);
229 row += dst->pitch;
230 }
231 }
232 break;
233 case 2: {
234 GLushort *row = (GLushort *) get_pointer(dst, dstx, dsty);
235 for (i = 0; i < height; i++) {
236 for (j = 0; j < width; j++)
237 row[j] = value;
238 row += dst->pitch;
239 }
240 }
241 break;
242 case 4: {
243 GLuint *row = (GLuint *) get_pointer(dst, dstx, dsty);
244 for (i = 0; i < height; i++) {
245 for (j = 0; j < width; j++)
246 row[j] = value;
247 row += dst->pitch;
248 }
249 }
250 break;
251 default:
252 assert(0);
253 break;
254 }
255
256 pipe->region_unmap( pipe, dst );
257 }
258
259
260
261
262
263 void
264 sp_init_region_functions(struct softpipe_context *sp)
265 {
266 sp->pipe.region_idle = sp_region_idle;
267 sp->pipe.region_map = sp_region_map;
268 sp->pipe.region_unmap = sp_region_unmap;
269 sp->pipe.region_alloc = sp_region_alloc;
270 sp->pipe.region_release = sp_region_release;
271 sp->pipe.region_data = sp_region_data;
272 sp->pipe.region_copy = sp_region_copy;
273 sp->pipe.region_fill = sp_region_fill;
274 }
275