nv50_surface.c revision b2dcf880e8bcd61be59602f5a2d18c77a5fc60c1
1/* 2 * Copyright 2008 Ben Skeggs 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 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * SOFTWARE. 21 */ 22 23#include <stdint.h> 24 25#include "pipe/p_defines.h" 26 27#include "util/u_inlines.h" 28#include "util/u_pack_color.h" 29#include "util/u_format.h" 30#include "util/u_surface.h" 31 32#include "nv50_context.h" 33#include "nv50_resource.h" 34 35#include "nv50_defs.xml.h" 36 37#define NV50_ENG2D_SUPPORTED_FORMATS 0xff0843e080608409ULL 38 39/* return TRUE for formats that can be converted among each other by NV50_2D */ 40static INLINE boolean 41nv50_2d_format_faithful(enum pipe_format format) 42{ 43 uint8_t id = nv50_format_table[format].rt; 44 45 return (id >= 0xc0) && 46 (NV50_ENG2D_SUPPORTED_FORMATS & (1ULL << (id - 0xc0))); 47} 48 49static INLINE uint8_t 50nv50_2d_format(enum pipe_format format) 51{ 52 uint8_t id = nv50_format_table[format].rt; 53 54 /* Hardware values for color formats range from 0xc0 to 0xff, 55 * but the 2D engine doesn't support all of them. 56 */ 57 if ((id >= 0xc0) && (NV50_ENG2D_SUPPORTED_FORMATS & (1ULL << (id - 0xc0)))) 58 return id; 59 60 switch (util_format_get_blocksize(format)) { 61 case 1: 62 return NV50_SURFACE_FORMAT_R8_UNORM; 63 case 2: 64 return NV50_SURFACE_FORMAT_R16_UNORM; 65 case 4: 66 return NV50_SURFACE_FORMAT_A8R8G8B8_UNORM; 67 default: 68 return 0; 69 } 70} 71 72static int 73nv50_2d_texture_set(struct nouveau_channel *chan, int dst, 74 struct nv50_miptree *mt, unsigned level, unsigned layer) 75{ 76 struct nouveau_bo *bo = mt->base.bo; 77 uint32_t width, height, depth; 78 uint32_t format; 79 uint32_t mthd = dst ? NV50_2D_DST_FORMAT : NV50_2D_SRC_FORMAT; 80 uint32_t flags = mt->base.domain | (dst ? NOUVEAU_BO_WR : NOUVEAU_BO_RD); 81 uint32_t offset = mt->level[level].offset; 82 83 format = nv50_2d_format(mt->base.base.format); 84 if (!format) { 85 NOUVEAU_ERR("invalid/unsupported surface format: %s\n", 86 util_format_name(mt->base.base.format)); 87 return 1; 88 } 89 90 width = u_minify(mt->base.base.width0, level) << mt->ms_x; 91 height = u_minify(mt->base.base.height0, level) << mt->ms_y; 92 93 offset = mt->level[level].offset; 94 if (!mt->layout_3d) { 95 offset += mt->layer_stride * layer; 96 depth = 1; 97 layer = 0; 98 } else { 99 depth = u_minify(mt->base.base.depth0, level); 100 } 101 102 if (!(bo->tile_flags & NOUVEAU_BO_TILE_LAYOUT_MASK)) { 103 BEGIN_RING(chan, RING_2D_(mthd), 2); 104 OUT_RING (chan, format); 105 OUT_RING (chan, 1); 106 BEGIN_RING(chan, RING_2D_(mthd + 0x14), 5); 107 OUT_RING (chan, mt->level[level].pitch); 108 OUT_RING (chan, width); 109 OUT_RING (chan, height); 110 OUT_RELOCh(chan, bo, offset, flags); 111 OUT_RELOCl(chan, bo, offset, flags); 112 } else { 113 BEGIN_RING(chan, RING_2D_(mthd), 5); 114 OUT_RING (chan, format); 115 OUT_RING (chan, 0); 116 OUT_RING (chan, mt->level[level].tile_mode << 4); 117 OUT_RING (chan, depth); 118 OUT_RING (chan, layer); 119 BEGIN_RING(chan, RING_2D_(mthd + 0x18), 4); 120 OUT_RING (chan, width); 121 OUT_RING (chan, height); 122 OUT_RELOCh(chan, bo, offset, flags); 123 OUT_RELOCl(chan, bo, offset, flags); 124 } 125 126#if 0 127 if (dst) { 128 BEGIN_RING(chan, RING_2D_(NV50_2D_CLIP_X), 4); 129 OUT_RING (chan, 0); 130 OUT_RING (chan, 0); 131 OUT_RING (chan, width); 132 OUT_RING (chan, height); 133 } 134#endif 135 return 0; 136} 137 138static int 139nv50_2d_texture_do_copy(struct nouveau_channel *chan, 140 struct nv50_miptree *dst, unsigned dst_level, 141 unsigned dx, unsigned dy, unsigned dz, 142 struct nv50_miptree *src, unsigned src_level, 143 unsigned sx, unsigned sy, unsigned sz, 144 unsigned w, unsigned h) 145{ 146 static const uint32_t duvdxy[5] = 147 { 148 0x40000000, 0x80000000, 0x00000001, 0x00000002, 0x00000004 149 }; 150 151 int ret; 152 uint32_t ctrl; 153 154 ret = MARK_RING(chan, 2 * 16 + 32, 4); 155 if (ret) 156 return ret; 157 158 ret = nv50_2d_texture_set(chan, 1, dst, dst_level, dz); 159 if (ret) 160 return ret; 161 162 ret = nv50_2d_texture_set(chan, 0, src, src_level, sz); 163 if (ret) 164 return ret; 165 166 /* NOTE: 2D engine doesn't work for MS8 */ 167 if (src->ms_x) 168 ctrl = 0x11; 169 170 /* 0/1 = CENTER/CORNER, 00/10 = POINT/BILINEAR */ 171 BEGIN_RING(chan, RING_2D(BLIT_CONTROL), 1); 172 OUT_RING (chan, ctrl); 173 BEGIN_RING(chan, RING_2D(BLIT_DST_X), 4); 174 OUT_RING (chan, dx << dst->ms_x); 175 OUT_RING (chan, dy << dst->ms_y); 176 OUT_RING (chan, w << dst->ms_x); 177 OUT_RING (chan, h << dst->ms_y); 178 BEGIN_RING(chan, RING_2D(BLIT_DU_DX_FRACT), 4); 179 OUT_RING (chan, duvdxy[2 + ((int)src->ms_x - (int)dst->ms_x)] & 0xf0000000); 180 OUT_RING (chan, duvdxy[2 + ((int)src->ms_x - (int)dst->ms_x)] & 0x0000000f); 181 OUT_RING (chan, duvdxy[2 + ((int)src->ms_y - (int)dst->ms_y)] & 0xf0000000); 182 OUT_RING (chan, duvdxy[2 + ((int)src->ms_y - (int)dst->ms_y)] & 0x0000000f); 183 BEGIN_RING(chan, RING_2D(BLIT_SRC_X_FRACT), 4); 184 OUT_RING (chan, 0); 185 OUT_RING (chan, sx << src->ms_x); 186 OUT_RING (chan, 0); 187 OUT_RING (chan, sy << src->ms_y); 188 189 return 0; 190} 191 192static void 193nv50_resource_copy_region(struct pipe_context *pipe, 194 struct pipe_resource *dst, unsigned dst_level, 195 unsigned dstx, unsigned dsty, unsigned dstz, 196 struct pipe_resource *src, unsigned src_level, 197 const struct pipe_box *src_box) 198{ 199 struct nv50_screen *screen = nv50_context(pipe)->screen; 200 int ret; 201 unsigned dst_layer = dstz, src_layer = src_box->z; 202 203 /* Fallback for buffers. */ 204 if (dst->target == PIPE_BUFFER && src->target == PIPE_BUFFER) { 205 util_resource_copy_region(pipe, dst, dst_level, dstx, dsty, dstz, 206 src, src_level, src_box); 207 return; 208 } 209 210 nv04_resource(dst)->status |= NOUVEAU_BUFFER_STATUS_GPU_WRITING; 211 212 if (src->format == dst->format && src->nr_samples == dst->nr_samples) { 213 struct nv50_m2mf_rect drect, srect; 214 unsigned i; 215 unsigned nx = util_format_get_nblocksx(src->format, src_box->width); 216 unsigned ny = util_format_get_nblocksy(src->format, src_box->height); 217 218 nv50_m2mf_rect_setup(&drect, dst, dst_level, dstx, dsty, dstz); 219 nv50_m2mf_rect_setup(&srect, src, src_level, 220 src_box->x, src_box->y, src_box->z); 221 222 for (i = 0; i < src_box->depth; ++i) { 223 nv50_m2mf_transfer_rect(&screen->base.base, &drect, &srect, nx, ny); 224 225 if (nv50_miptree(dst)->layout_3d) 226 drect.z++; 227 else 228 drect.base += nv50_miptree(dst)->layer_stride; 229 230 if (nv50_miptree(src)->layout_3d) 231 srect.z++; 232 else 233 srect.base += nv50_miptree(src)->layer_stride; 234 } 235 return; 236 } 237 238 assert((src->format == dst->format) || 239 (nv50_2d_format_faithful(src->format) && 240 nv50_2d_format_faithful(dst->format))); 241 242 for (; dst_layer < dstz + src_box->depth; ++dst_layer, ++src_layer) { 243 ret = nv50_2d_texture_do_copy(screen->base.channel, 244 nv50_miptree(dst), dst_level, 245 dstx, dsty, dst_layer, 246 nv50_miptree(src), src_level, 247 src_box->x, src_box->y, src_layer, 248 src_box->width, src_box->height); 249 if (ret) 250 return; 251 } 252} 253 254static void 255nv50_clear_render_target(struct pipe_context *pipe, 256 struct pipe_surface *dst, 257 const float *rgba, 258 unsigned dstx, unsigned dsty, 259 unsigned width, unsigned height) 260{ 261 struct nv50_context *nv50 = nv50_context(pipe); 262 struct nv50_screen *screen = nv50->screen; 263 struct nouveau_channel *chan = screen->base.channel; 264 struct nv50_miptree *mt = nv50_miptree(dst->texture); 265 struct nv50_surface *sf = nv50_surface(dst); 266 struct nouveau_bo *bo = mt->base.bo; 267 268 BEGIN_RING(chan, RING_3D(CLEAR_COLOR(0)), 4); 269 OUT_RINGf (chan, rgba[0]); 270 OUT_RINGf (chan, rgba[1]); 271 OUT_RINGf (chan, rgba[2]); 272 OUT_RINGf (chan, rgba[3]); 273 274 if (MARK_RING(chan, 18, 2)) 275 return; 276 277 BEGIN_RING(chan, RING_3D(RT_CONTROL), 1); 278 OUT_RING (chan, 1); 279 BEGIN_RING(chan, RING_3D(RT_ADDRESS_HIGH(0)), 5); 280 OUT_RELOCh(chan, bo, sf->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); 281 OUT_RELOCl(chan, bo, sf->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); 282 OUT_RING (chan, nv50_format_table[dst->format].rt); 283 OUT_RING (chan, mt->level[sf->base.u.tex.level].tile_mode << 4); 284 OUT_RING (chan, 0); 285 BEGIN_RING(chan, RING_3D(RT_HORIZ(0)), 2); 286 OUT_RING (chan, sf->width); 287 OUT_RING (chan, sf->height); 288 BEGIN_RING(chan, RING_3D(RT_ARRAY_MODE), 1); 289 OUT_RING (chan, 1); 290 291 /* NOTE: only works with D3D clear flag (5097/0x143c bit 4) */ 292 293 BEGIN_RING(chan, RING_3D(VIEWPORT_HORIZ(0)), 2); 294 OUT_RING (chan, (width << 16) | dstx); 295 OUT_RING (chan, (height << 16) | dsty); 296 297 BEGIN_RING(chan, RING_3D(CLEAR_BUFFERS), 1); 298 OUT_RING (chan, 0x3c); 299 300 nv50->dirty |= NV50_NEW_FRAMEBUFFER; 301} 302 303static void 304nv50_clear_depth_stencil(struct pipe_context *pipe, 305 struct pipe_surface *dst, 306 unsigned clear_flags, 307 double depth, 308 unsigned stencil, 309 unsigned dstx, unsigned dsty, 310 unsigned width, unsigned height) 311{ 312 struct nv50_context *nv50 = nv50_context(pipe); 313 struct nv50_screen *screen = nv50->screen; 314 struct nouveau_channel *chan = screen->base.channel; 315 struct nv50_miptree *mt = nv50_miptree(dst->texture); 316 struct nv50_surface *sf = nv50_surface(dst); 317 struct nouveau_bo *bo = mt->base.bo; 318 uint32_t mode = 0; 319 320 if (clear_flags & PIPE_CLEAR_DEPTH) { 321 BEGIN_RING(chan, RING_3D(CLEAR_DEPTH), 1); 322 OUT_RINGf (chan, depth); 323 mode |= NV50_3D_CLEAR_BUFFERS_Z; 324 } 325 326 if (clear_flags & PIPE_CLEAR_STENCIL) { 327 BEGIN_RING(chan, RING_3D(CLEAR_STENCIL), 1); 328 OUT_RING (chan, stencil & 0xff); 329 mode |= NV50_3D_CLEAR_BUFFERS_S; 330 } 331 332 if (MARK_RING(chan, 17, 2)) 333 return; 334 335 BEGIN_RING(chan, RING_3D(ZETA_ADDRESS_HIGH), 5); 336 OUT_RELOCh(chan, bo, sf->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); 337 OUT_RELOCl(chan, bo, sf->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); 338 OUT_RING (chan, nv50_format_table[dst->format].rt); 339 OUT_RING (chan, mt->level[sf->base.u.tex.level].tile_mode << 4); 340 OUT_RING (chan, 0); 341 BEGIN_RING(chan, RING_3D(ZETA_ENABLE), 1); 342 OUT_RING (chan, 1); 343 BEGIN_RING(chan, RING_3D(ZETA_HORIZ), 3); 344 OUT_RING (chan, sf->width); 345 OUT_RING (chan, sf->height); 346 OUT_RING (chan, (1 << 16) | 1); 347 348 BEGIN_RING(chan, RING_3D(VIEWPORT_HORIZ(0)), 2); 349 OUT_RING (chan, (width << 16) | dstx); 350 OUT_RING (chan, (height << 16) | dsty); 351 352 BEGIN_RING(chan, RING_3D(CLEAR_BUFFERS), 1); 353 OUT_RING (chan, mode); 354 355 nv50->dirty |= NV50_NEW_FRAMEBUFFER; 356} 357 358void 359nv50_clear(struct pipe_context *pipe, unsigned buffers, 360 const float *rgba, double depth, unsigned stencil) 361{ 362 struct nv50_context *nv50 = nv50_context(pipe); 363 struct nouveau_channel *chan = nv50->screen->base.channel; 364 struct pipe_framebuffer_state *fb = &nv50->framebuffer; 365 unsigned i; 366 const unsigned dirty = nv50->dirty; 367 uint32_t mode = 0; 368 369 /* don't need NEW_BLEND, COLOR_MASK doesn't affect CLEAR_BUFFERS */ 370 nv50->dirty &= NV50_NEW_FRAMEBUFFER; 371 if (!nv50_state_validate(nv50)) 372 return; 373 374 if (buffers & PIPE_CLEAR_COLOR && fb->nr_cbufs) { 375 BEGIN_RING(chan, RING_3D(CLEAR_COLOR(0)), 4); 376 OUT_RINGf (chan, rgba[0]); 377 OUT_RINGf (chan, rgba[1]); 378 OUT_RINGf (chan, rgba[2]); 379 OUT_RINGf (chan, rgba[3]); 380 mode = 381 NV50_3D_CLEAR_BUFFERS_R | NV50_3D_CLEAR_BUFFERS_G | 382 NV50_3D_CLEAR_BUFFERS_B | NV50_3D_CLEAR_BUFFERS_A; 383 } 384 385 if (buffers & PIPE_CLEAR_DEPTH) { 386 BEGIN_RING(chan, RING_3D(CLEAR_DEPTH), 1); 387 OUT_RING (chan, fui(depth)); 388 mode |= NV50_3D_CLEAR_BUFFERS_Z; 389 } 390 391 if (buffers & PIPE_CLEAR_STENCIL) { 392 BEGIN_RING(chan, RING_3D(CLEAR_STENCIL), 1); 393 OUT_RING (chan, stencil & 0xff); 394 mode |= NV50_3D_CLEAR_BUFFERS_S; 395 } 396 397 BEGIN_RING(chan, RING_3D(CLEAR_BUFFERS), 1); 398 OUT_RING (chan, mode); 399 400 for (i = 1; i < fb->nr_cbufs; i++) { 401 BEGIN_RING(chan, RING_3D(CLEAR_BUFFERS), 1); 402 OUT_RING (chan, (i << 6) | 0x3c); 403 } 404 405 nv50->dirty = dirty & ~NV50_NEW_FRAMEBUFFER; 406} 407 408void 409nv50_init_surface_functions(struct nv50_context *nv50) 410{ 411 struct pipe_context *pipe = &nv50->base.pipe; 412 413 pipe->resource_copy_region = nv50_resource_copy_region; 414 pipe->clear_render_target = nv50_clear_render_target; 415 pipe->clear_depth_stencil = nv50_clear_depth_stencil; 416} 417 418 419