1 /*
2 * Copyright 2011 Joakim Sindholt <opensource@zhasha.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 "iunknown.h"
24 #include "surface9.h"
25 #include "device9.h"
26
27 /* for marking dirty */
28 #include "basetexture9.h"
29 #include "texture9.h"
30 #include "cubetexture9.h"
31
32 #include "nine_helpers.h"
33 #include "nine_pipe.h"
34 #include "nine_dump.h"
35 #include "nine_state.h"
36
37 #include "pipe/p_context.h"
38 #include "pipe/p_screen.h"
39 #include "pipe/p_state.h"
40
41 #include "util/u_math.h"
42 #include "util/u_inlines.h"
43 #include "util/u_surface.h"
44
45 #define DBG_CHANNEL DBG_SURFACE
46
47 static void
48 NineSurface9_CreatePipeSurfaces( struct NineSurface9 *This );
49
50 HRESULT
NineSurface9_ctor(struct NineSurface9 * This,struct NineUnknownParams * pParams,struct NineUnknown * pContainer,struct pipe_resource * pResource,void * user_buffer,uint8_t TextureType,unsigned Level,unsigned Layer,D3DSURFACE_DESC * pDesc)51 NineSurface9_ctor( struct NineSurface9 *This,
52 struct NineUnknownParams *pParams,
53 struct NineUnknown *pContainer,
54 struct pipe_resource *pResource,
55 void *user_buffer,
56 uint8_t TextureType,
57 unsigned Level,
58 unsigned Layer,
59 D3DSURFACE_DESC *pDesc )
60 {
61 HRESULT hr;
62 bool allocate = !pContainer && pDesc->Format != D3DFMT_NULL;
63 D3DMULTISAMPLE_TYPE multisample_type;
64
65 DBG("This=%p pDevice=%p pResource=%p Level=%u Layer=%u pDesc=%p\n",
66 This, pParams->device, pResource, Level, Layer, pDesc);
67
68 /* Mark this as a special surface held by another internal resource. */
69 pParams->container = pContainer;
70 /* Make sure there's a Desc */
71 assert(pDesc);
72
73 assert(allocate || pResource || user_buffer ||
74 pDesc->Format == D3DFMT_NULL);
75 assert(!allocate || (!pResource && !user_buffer));
76 assert(!pResource || !user_buffer);
77 assert(!user_buffer || pDesc->Pool != D3DPOOL_DEFAULT);
78 assert(!pResource || pDesc->Pool == D3DPOOL_DEFAULT);
79 /* Allocation only from create_zs_or_rt_surface with params 0 0 0 */
80 assert(!allocate || (Level == 0 && Layer == 0 && TextureType == 0));
81
82 This->data = (uint8_t *)user_buffer;
83
84 multisample_type = pDesc->MultiSampleType;
85
86 /* Map MultiSampleQuality to MultiSampleType */
87 hr = d3dmultisample_type_check(pParams->device->screen,
88 pDesc->Format,
89 &multisample_type,
90 pDesc->MultiSampleQuality,
91 NULL);
92 if (FAILED(hr)) {
93 return hr;
94 }
95
96 /* TODO: this is (except width and height) duplicate from
97 * container info (in the pContainer case). Some refactoring is
98 * needed to avoid duplication */
99 This->base.info.screen = pParams->device->screen;
100 This->base.info.target = PIPE_TEXTURE_2D;
101 This->base.info.width0 = pDesc->Width;
102 This->base.info.height0 = pDesc->Height;
103 This->base.info.depth0 = 1;
104 This->base.info.last_level = 0;
105 This->base.info.array_size = 1;
106 This->base.info.nr_samples = multisample_type;
107 This->base.info.usage = PIPE_USAGE_DEFAULT;
108 This->base.info.bind = PIPE_BIND_SAMPLER_VIEW; /* StretchRect */
109
110 if (pDesc->Usage & D3DUSAGE_RENDERTARGET) {
111 This->base.info.bind |= PIPE_BIND_RENDER_TARGET;
112 } else if (pDesc->Usage & D3DUSAGE_DEPTHSTENCIL) {
113 This->base.info.bind = d3d9_get_pipe_depth_format_bindings(pDesc->Format);
114 if (TextureType)
115 This->base.info.bind |= PIPE_BIND_SAMPLER_VIEW;
116 }
117
118 This->base.info.flags = 0;
119 This->base.info.format = d3d9_to_pipe_format_checked(This->base.info.screen,
120 pDesc->Format,
121 This->base.info.target,
122 This->base.info.nr_samples,
123 This->base.info.bind,
124 FALSE,
125 pDesc->Pool == D3DPOOL_SCRATCH);
126
127 if (This->base.info.format == PIPE_FORMAT_NONE && pDesc->Format != D3DFMT_NULL)
128 return D3DERR_INVALIDCALL;
129
130 if (allocate && compressed_format(pDesc->Format)) {
131 const unsigned w = util_format_get_blockwidth(This->base.info.format);
132 const unsigned h = util_format_get_blockheight(This->base.info.format);
133
134 /* Note: In the !allocate case, the test could fail (lower levels of a texture) */
135 user_assert(!(pDesc->Width % w) && !(pDesc->Height % h), D3DERR_INVALIDCALL);
136 }
137
138 /* Get true format */
139 This->format_conversion = d3d9_to_pipe_format_checked(This->base.info.screen,
140 pDesc->Format,
141 This->base.info.target,
142 This->base.info.nr_samples,
143 This->base.info.bind,
144 FALSE,
145 TRUE);
146 if (This->base.info.format != This->format_conversion) {
147 This->data_conversion = align_calloc(
148 nine_format_get_level_alloc_size(This->format_conversion,
149 pDesc->Width,
150 pDesc->Height,
151 0), 32);
152 if (!This->data_conversion)
153 return E_OUTOFMEMORY;
154 This->stride_conversion = nine_format_get_stride(This->format_conversion,
155 pDesc->Width);
156 }
157
158 if ((allocate && pDesc->Pool != D3DPOOL_DEFAULT) || pDesc->Format == D3DFMT_NULL) {
159 /* Ram buffer with no parent. Has to allocate the resource itself */
160 assert(!user_buffer);
161 This->data = align_calloc(
162 nine_format_get_level_alloc_size(This->base.info.format,
163 pDesc->Width,
164 pDesc->Height,
165 0), 32);
166 if (!This->data)
167 return E_OUTOFMEMORY;
168 }
169
170 hr = NineResource9_ctor(&This->base, pParams, pResource,
171 allocate && (pDesc->Pool == D3DPOOL_DEFAULT),
172 D3DRTYPE_SURFACE, pDesc->Pool, pDesc->Usage);
173
174 if (FAILED(hr))
175 return hr;
176
177 This->transfer = NULL;
178
179 This->texture = TextureType;
180 This->level = Level;
181 This->level_actual = Level;
182 This->layer = Layer;
183 This->desc = *pDesc;
184
185 This->stride = nine_format_get_stride(This->base.info.format, pDesc->Width);
186
187 if (This->base.resource && (pDesc->Usage & D3DUSAGE_DYNAMIC))
188 This->base.resource->flags |= NINE_RESOURCE_FLAG_LOCKABLE;
189
190 if (This->base.resource && (pDesc->Usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)))
191 NineSurface9_CreatePipeSurfaces(This);
192
193 /* TODO: investigate what else exactly needs to be cleared */
194 if (This->base.resource && (pDesc->Usage & D3DUSAGE_RENDERTARGET))
195 nine_context_clear_render_target(pParams->device, This, 0, 0, 0, pDesc->Width, pDesc->Height);
196
197 NineSurface9_Dump(This);
198
199 return D3D_OK;
200 }
201
202 void
NineSurface9_dtor(struct NineSurface9 * This)203 NineSurface9_dtor( struct NineSurface9 *This )
204 {
205 DBG("This=%p\n", This);
206
207 if (This->transfer) {
208 struct pipe_context *pipe = nine_context_get_pipe_multithread(This->base.base.device);
209 pipe->transfer_unmap(pipe, This->transfer);
210 This->transfer = NULL;
211 }
212
213 /* Note: Following condition cannot happen currently, since we
214 * refcount the surface in the functions increasing
215 * pending_uploads_counter. */
216 if (p_atomic_read(&This->pending_uploads_counter))
217 nine_csmt_process(This->base.base.device);
218
219 pipe_surface_reference(&This->surface[0], NULL);
220 pipe_surface_reference(&This->surface[1], NULL);
221
222 /* Release system memory when we have to manage it (no parent) */
223 if (!This->base.base.container && This->data)
224 align_free(This->data);
225 if (This->data_conversion)
226 align_free(This->data_conversion);
227 NineResource9_dtor(&This->base);
228 }
229
230 static void
NineSurface9_CreatePipeSurfaces(struct NineSurface9 * This)231 NineSurface9_CreatePipeSurfaces( struct NineSurface9 *This )
232 {
233 struct pipe_context *pipe;
234 struct pipe_screen *screen = NineDevice9_GetScreen(This->base.base.device);
235 struct pipe_resource *resource = This->base.resource;
236 struct pipe_surface templ;
237 enum pipe_format srgb_format;
238
239 assert(This->desc.Pool == D3DPOOL_DEFAULT);
240 assert(resource);
241
242 srgb_format = util_format_srgb(resource->format);
243 if (srgb_format == PIPE_FORMAT_NONE ||
244 !screen->is_format_supported(screen, srgb_format,
245 resource->target, 0, resource->bind))
246 srgb_format = resource->format;
247
248 memset(&templ, 0, sizeof(templ));
249 templ.format = resource->format;
250 templ.u.tex.level = This->level;
251 templ.u.tex.first_layer = This->layer;
252 templ.u.tex.last_layer = This->layer;
253
254 pipe = nine_context_get_pipe_acquire(This->base.base.device);
255
256 This->surface[0] = pipe->create_surface(pipe, resource, &templ);
257
258 memset(&templ, 0, sizeof(templ));
259 templ.format = srgb_format;
260 templ.u.tex.level = This->level;
261 templ.u.tex.first_layer = This->layer;
262 templ.u.tex.last_layer = This->layer;
263
264 This->surface[1] = pipe->create_surface(pipe, resource, &templ);
265
266 nine_context_get_pipe_release(This->base.base.device);
267
268 assert(This->surface[0]); /* TODO: Handle failure */
269 assert(This->surface[1]);
270 }
271
272 #ifdef DEBUG
273 void
NineSurface9_Dump(struct NineSurface9 * This)274 NineSurface9_Dump( struct NineSurface9 *This )
275 {
276 struct NineBaseTexture9 *tex;
277 GUID id = IID_IDirect3DBaseTexture9;
278 REFIID ref = &id;
279
280 DBG("\nNineSurface9(%p->%p/%p): Pool=%s Type=%s Usage=%s\n"
281 "Dims=%ux%u Format=%s Stride=%u Lockable=%i\n"
282 "Level=%u(%u), Layer=%u\n", This, This->base.resource, This->data,
283 nine_D3DPOOL_to_str(This->desc.Pool),
284 nine_D3DRTYPE_to_str(This->desc.Type),
285 nine_D3DUSAGE_to_str(This->desc.Usage),
286 This->desc.Width, This->desc.Height,
287 d3dformat_to_string(This->desc.Format), This->stride,
288 This->base.resource &&
289 (This->base.resource->flags & NINE_RESOURCE_FLAG_LOCKABLE),
290 This->level, This->level_actual, This->layer);
291
292 if (!This->base.base.container)
293 return;
294 NineUnknown_QueryInterface(This->base.base.container, ref, (void **)&tex);
295 if (tex) {
296 NineBaseTexture9_Dump(tex);
297 NineUnknown_Release(NineUnknown(tex));
298 }
299 }
300 #endif /* DEBUG */
301
302 HRESULT NINE_WINAPI
NineSurface9_GetContainer(struct NineSurface9 * This,REFIID riid,void ** ppContainer)303 NineSurface9_GetContainer( struct NineSurface9 *This,
304 REFIID riid,
305 void **ppContainer )
306 {
307 HRESULT hr;
308 char guid_str[64];
309
310 DBG("This=%p riid=%p id=%s ppContainer=%p\n",
311 This, riid, riid ? GUID_sprintf(guid_str, riid) : "", ppContainer);
312
313 (void)guid_str;
314
315 if (!ppContainer) return E_POINTER;
316
317 /* Return device for OffscreenPlainSurface, DepthStencilSurface and RenderTarget */
318 if (!NineUnknown(This)->container) {
319 *ppContainer = NineUnknown(This)->device;
320 NineUnknown_AddRef(NineUnknown(*ppContainer));
321
322 return D3D_OK;
323 }
324
325 hr = NineUnknown_QueryInterface(NineUnknown(This)->container, riid, ppContainer);
326 if (FAILED(hr))
327 DBG("QueryInterface FAILED!\n");
328 return hr;
329 }
330
331 void
NineSurface9_MarkContainerDirty(struct NineSurface9 * This)332 NineSurface9_MarkContainerDirty( struct NineSurface9 *This )
333 {
334 if (This->texture) {
335 struct NineBaseTexture9 *tex =
336 NineBaseTexture9(This->base.base.container);
337 assert(tex);
338 assert(This->texture == D3DRTYPE_TEXTURE ||
339 This->texture == D3DRTYPE_CUBETEXTURE);
340 if (This->base.pool == D3DPOOL_MANAGED)
341 tex->managed.dirty = TRUE;
342 else
343 if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP)
344 tex->dirty_mip = TRUE;
345
346 BASETEX_REGISTER_UPDATE(tex);
347 }
348 }
349
350 HRESULT NINE_WINAPI
NineSurface9_GetDesc(struct NineSurface9 * This,D3DSURFACE_DESC * pDesc)351 NineSurface9_GetDesc( struct NineSurface9 *This,
352 D3DSURFACE_DESC *pDesc )
353 {
354 user_assert(pDesc != NULL, E_POINTER);
355 *pDesc = This->desc;
356 return D3D_OK;
357 }
358
359 /* Add the dirty rects to the source texture */
360 inline void
NineSurface9_AddDirtyRect(struct NineSurface9 * This,const struct pipe_box * box)361 NineSurface9_AddDirtyRect( struct NineSurface9 *This,
362 const struct pipe_box *box )
363 {
364 RECT dirty_rect;
365
366 DBG("This=%p box=%p\n", This, box);
367
368 assert (This->base.pool != D3DPOOL_MANAGED ||
369 This->texture == D3DRTYPE_CUBETEXTURE ||
370 This->texture == D3DRTYPE_TEXTURE);
371
372 if (This->base.pool == D3DPOOL_DEFAULT)
373 return;
374
375 /* Add a dirty rect to level 0 of the parent texture */
376 dirty_rect.left = box->x << This->level_actual;
377 dirty_rect.right = dirty_rect.left + (box->width << This->level_actual);
378 dirty_rect.top = box->y << This->level_actual;
379 dirty_rect.bottom = dirty_rect.top + (box->height << This->level_actual);
380
381 if (This->texture == D3DRTYPE_TEXTURE) {
382 struct NineTexture9 *tex =
383 NineTexture9(This->base.base.container);
384
385 NineTexture9_AddDirtyRect(tex, &dirty_rect);
386 } else if (This->texture == D3DRTYPE_CUBETEXTURE) {
387 struct NineCubeTexture9 *ctex =
388 NineCubeTexture9(This->base.base.container);
389
390 NineCubeTexture9_AddDirtyRect(ctex, This->layer, &dirty_rect);
391 }
392 }
393
394 static inline uint8_t *
NineSurface9_GetSystemMemPointer(struct NineSurface9 * This,int x,int y)395 NineSurface9_GetSystemMemPointer(struct NineSurface9 *This, int x, int y)
396 {
397 unsigned x_offset = util_format_get_stride(This->base.info.format, x);
398
399 y = util_format_get_nblocksy(This->base.info.format, y);
400
401 assert(This->data);
402 return This->data + (y * This->stride + x_offset);
403 }
404
405 HRESULT NINE_WINAPI
NineSurface9_LockRect(struct NineSurface9 * This,D3DLOCKED_RECT * pLockedRect,const RECT * pRect,DWORD Flags)406 NineSurface9_LockRect( struct NineSurface9 *This,
407 D3DLOCKED_RECT *pLockedRect,
408 const RECT *pRect,
409 DWORD Flags )
410 {
411 struct pipe_resource *resource = This->base.resource;
412 struct pipe_context *pipe;
413 struct pipe_box box;
414 unsigned usage;
415
416 DBG("This=%p pLockedRect=%p pRect=%p[%u..%u,%u..%u] Flags=%s\n", This,
417 pLockedRect, pRect,
418 pRect ? pRect->left : 0, pRect ? pRect->right : 0,
419 pRect ? pRect->top : 0, pRect ? pRect->bottom : 0,
420 nine_D3DLOCK_to_str(Flags));
421 NineSurface9_Dump(This);
422
423 /* check if it's already locked */
424 user_assert(This->lock_count == 0, D3DERR_INVALIDCALL);
425
426 /* set pBits to NULL after lock_count check */
427 user_assert(pLockedRect, E_POINTER);
428 pLockedRect->pBits = NULL;
429
430 #ifdef NINE_STRICT
431 user_assert(This->base.pool != D3DPOOL_DEFAULT ||
432 (resource && (resource->flags & NINE_RESOURCE_FLAG_LOCKABLE)),
433 D3DERR_INVALIDCALL);
434 #endif
435 user_assert(!(Flags & ~(D3DLOCK_DISCARD |
436 D3DLOCK_DONOTWAIT |
437 D3DLOCK_NO_DIRTY_UPDATE |
438 D3DLOCK_NOOVERWRITE |
439 D3DLOCK_NOSYSLOCK | /* ignored */
440 D3DLOCK_READONLY)), D3DERR_INVALIDCALL);
441 user_assert(!((Flags & D3DLOCK_DISCARD) && (Flags & D3DLOCK_READONLY)),
442 D3DERR_INVALIDCALL);
443
444 user_assert(This->desc.MultiSampleType == D3DMULTISAMPLE_NONE,
445 D3DERR_INVALIDCALL);
446
447 if (pRect && This->desc.Pool == D3DPOOL_DEFAULT &&
448 util_format_is_compressed(This->base.info.format)) {
449 const unsigned w = util_format_get_blockwidth(This->base.info.format);
450 const unsigned h = util_format_get_blockheight(This->base.info.format);
451 user_assert((pRect->left == 0 && pRect->right == This->desc.Width &&
452 pRect->top == 0 && pRect->bottom == This->desc.Height) ||
453 (!(pRect->left % w) && !(pRect->right % w) &&
454 !(pRect->top % h) && !(pRect->bottom % h)),
455 D3DERR_INVALIDCALL);
456 }
457
458 if (Flags & D3DLOCK_DISCARD) {
459 usage = PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE;
460 } else {
461 usage = (Flags & D3DLOCK_READONLY) ?
462 PIPE_TRANSFER_READ : PIPE_TRANSFER_READ_WRITE;
463 }
464 if (Flags & D3DLOCK_DONOTWAIT)
465 usage |= PIPE_TRANSFER_DONTBLOCK;
466
467 if (pRect) {
468 /* Windows XP accepts invalid locking rectangles, Windows 7 rejects
469 * them. Use Windows XP behaviour for now. */
470 rect_to_pipe_box(&box, pRect);
471 } else {
472 u_box_origin_2d(This->desc.Width, This->desc.Height, &box);
473 }
474 box.z = This->layer;
475
476 user_warn(This->desc.Format == D3DFMT_NULL);
477
478 if (p_atomic_read(&This->pending_uploads_counter))
479 nine_csmt_process(This->base.base.device);
480
481 if (This->data_conversion) {
482 /* For now we only have uncompressed formats here */
483 pLockedRect->Pitch = This->stride_conversion;
484 pLockedRect->pBits = This->data_conversion + box.y * This->stride_conversion +
485 util_format_get_stride(This->format_conversion, box.x);
486 } else if (This->data) {
487 DBG("returning system memory\n");
488 /* ATI1 and ATI2 need special handling, because of d3d9 bug.
489 * We must advertise to the application as if it is uncompressed
490 * and bpp 8, and the app has a workaround to work with the fact
491 * that it is actually compressed. */
492 if (is_ATI1_ATI2(This->base.info.format)) {
493 pLockedRect->Pitch = This->desc.Width;
494 pLockedRect->pBits = This->data + box.y * This->desc.Width + box.x;
495 } else {
496 pLockedRect->Pitch = This->stride;
497 pLockedRect->pBits = NineSurface9_GetSystemMemPointer(This,
498 box.x,
499 box.y);
500 }
501 } else {
502 bool no_refs = !p_atomic_read(&This->base.base.bind) &&
503 !(This->base.base.container && p_atomic_read(&This->base.base.container->bind));
504 DBG("mapping pipe_resource %p (level=%u usage=%x)\n",
505 resource, This->level, usage);
506
507 /* if the object is not bound internally, there can't be any pending
508 * operation with the surface in the queue */
509 if (no_refs)
510 pipe = nine_context_get_pipe_acquire(This->base.base.device);
511 else
512 pipe = NineDevice9_GetPipe(This->base.base.device);
513 pLockedRect->pBits = pipe->transfer_map(pipe, resource,
514 This->level, usage, &box,
515 &This->transfer);
516 if (no_refs)
517 nine_context_get_pipe_release(This->base.base.device);
518 if (!This->transfer) {
519 DBG("transfer_map failed\n");
520 if (Flags & D3DLOCK_DONOTWAIT)
521 return D3DERR_WASSTILLDRAWING;
522 return D3DERR_INVALIDCALL;
523 }
524 pLockedRect->Pitch = This->transfer->stride;
525 }
526
527 if (!(Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY))) {
528 NineSurface9_MarkContainerDirty(This);
529 NineSurface9_AddDirtyRect(This, &box);
530 }
531
532 ++This->lock_count;
533 return D3D_OK;
534 }
535
536 HRESULT NINE_WINAPI
NineSurface9_UnlockRect(struct NineSurface9 * This)537 NineSurface9_UnlockRect( struct NineSurface9 *This )
538 {
539 struct pipe_context *pipe;
540 DBG("This=%p lock_count=%u\n", This, This->lock_count);
541 user_assert(This->lock_count, D3DERR_INVALIDCALL);
542 if (This->transfer) {
543 pipe = nine_context_get_pipe_acquire(This->base.base.device);
544 pipe->transfer_unmap(pipe, This->transfer);
545 nine_context_get_pipe_release(This->base.base.device);
546 This->transfer = NULL;
547 }
548 --This->lock_count;
549
550 if (This->data_conversion) {
551 struct pipe_transfer *transfer;
552 uint8_t *dst = This->data;
553 struct pipe_box box;
554
555 u_box_origin_2d(This->desc.Width, This->desc.Height, &box);
556
557 pipe = NineDevice9_GetPipe(This->base.base.device);
558 if (!dst) {
559 dst = pipe->transfer_map(pipe,
560 This->base.resource,
561 This->level,
562 PIPE_TRANSFER_WRITE |
563 PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE,
564 &box, &transfer);
565 if (!dst)
566 return D3D_OK;
567 }
568
569 (void) util_format_translate(This->base.info.format,
570 dst, This->data ? This->stride : transfer->stride,
571 0, 0,
572 This->format_conversion,
573 This->data_conversion,
574 This->stride_conversion,
575 0, 0,
576 This->desc.Width, This->desc.Height);
577
578 if (!This->data)
579 pipe_transfer_unmap(pipe, transfer);
580 }
581 return D3D_OK;
582 }
583
584 HRESULT NINE_WINAPI
NineSurface9_GetDC(struct NineSurface9 * This,HDC * phdc)585 NineSurface9_GetDC( struct NineSurface9 *This,
586 HDC *phdc )
587 {
588 STUB(D3DERR_INVALIDCALL);
589 }
590
591 HRESULT NINE_WINAPI
NineSurface9_ReleaseDC(struct NineSurface9 * This,HDC hdc)592 NineSurface9_ReleaseDC( struct NineSurface9 *This,
593 HDC hdc )
594 {
595 STUB(D3DERR_INVALIDCALL);
596 }
597
598 IDirect3DSurface9Vtbl NineSurface9_vtable = {
599 (void *)NineUnknown_QueryInterface,
600 (void *)NineUnknown_AddRef,
601 (void *)NineUnknown_Release,
602 (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */
603 (void *)NineUnknown_SetPrivateData,
604 (void *)NineUnknown_GetPrivateData,
605 (void *)NineUnknown_FreePrivateData,
606 (void *)NineResource9_SetPriority,
607 (void *)NineResource9_GetPriority,
608 (void *)NineResource9_PreLoad,
609 (void *)NineResource9_GetType,
610 (void *)NineSurface9_GetContainer,
611 (void *)NineSurface9_GetDesc,
612 (void *)NineSurface9_LockRect,
613 (void *)NineSurface9_UnlockRect,
614 (void *)NineSurface9_GetDC,
615 (void *)NineSurface9_ReleaseDC
616 };
617
618 /* When this function is called, we have already checked
619 * The copy regions fit the surfaces */
620 void
NineSurface9_CopyMemToDefault(struct NineSurface9 * This,struct NineSurface9 * From,const POINT * pDestPoint,const RECT * pSourceRect)621 NineSurface9_CopyMemToDefault( struct NineSurface9 *This,
622 struct NineSurface9 *From,
623 const POINT *pDestPoint,
624 const RECT *pSourceRect )
625 {
626 struct pipe_resource *r_dst = This->base.resource;
627 struct pipe_box dst_box, src_box;
628 int src_x, src_y, dst_x, dst_y, copy_width, copy_height;
629
630 assert(This->base.pool == D3DPOOL_DEFAULT &&
631 From->base.pool == D3DPOOL_SYSTEMMEM);
632
633 if (pDestPoint) {
634 dst_x = pDestPoint->x;
635 dst_y = pDestPoint->y;
636 } else {
637 dst_x = 0;
638 dst_y = 0;
639 }
640
641 if (pSourceRect) {
642 src_x = pSourceRect->left;
643 src_y = pSourceRect->top;
644 copy_width = pSourceRect->right - pSourceRect->left;
645 copy_height = pSourceRect->bottom - pSourceRect->top;
646 } else {
647 src_x = 0;
648 src_y = 0;
649 copy_width = From->desc.Width;
650 copy_height = From->desc.Height;
651 }
652
653 u_box_2d_zslice(dst_x, dst_y, This->layer,
654 copy_width, copy_height, &dst_box);
655 u_box_2d_zslice(src_x, src_y, 0,
656 copy_width, copy_height, &src_box);
657
658 nine_context_box_upload(This->base.base.device,
659 &From->pending_uploads_counter,
660 (struct NineUnknown *)This,
661 r_dst,
662 This->level,
663 &dst_box,
664 From->base.info.format,
665 From->data, From->stride,
666 0, /* depth = 1 */
667 &src_box);
668
669 if (This->data_conversion)
670 (void) util_format_translate(This->format_conversion,
671 This->data_conversion,
672 This->stride_conversion,
673 dst_x, dst_y,
674 From->base.info.format,
675 From->data, From->stride,
676 src_x, src_y,
677 copy_width, copy_height);
678
679 NineSurface9_MarkContainerDirty(This);
680 }
681
682 void
NineSurface9_CopyDefaultToMem(struct NineSurface9 * This,struct NineSurface9 * From)683 NineSurface9_CopyDefaultToMem( struct NineSurface9 *This,
684 struct NineSurface9 *From )
685 {
686 struct pipe_context *pipe;
687 struct pipe_resource *r_src = From->base.resource;
688 struct pipe_transfer *transfer;
689 struct pipe_box src_box;
690 uint8_t *p_dst;
691 const uint8_t *p_src;
692
693 assert(This->base.pool == D3DPOOL_SYSTEMMEM &&
694 From->base.pool == D3DPOOL_DEFAULT);
695
696 assert(This->desc.Width == From->desc.Width);
697 assert(This->desc.Height == From->desc.Height);
698
699 u_box_origin_2d(This->desc.Width, This->desc.Height, &src_box);
700 src_box.z = From->layer;
701
702 if (p_atomic_read(&This->pending_uploads_counter))
703 nine_csmt_process(This->base.base.device);
704
705 pipe = NineDevice9_GetPipe(This->base.base.device);
706 p_src = pipe->transfer_map(pipe, r_src, From->level,
707 PIPE_TRANSFER_READ,
708 &src_box, &transfer);
709 p_dst = NineSurface9_GetSystemMemPointer(This, 0, 0);
710
711 assert (p_src && p_dst);
712
713 util_copy_rect(p_dst, This->base.info.format,
714 This->stride, 0, 0,
715 This->desc.Width, This->desc.Height,
716 p_src,
717 transfer->stride, 0, 0);
718
719 pipe->transfer_unmap(pipe, transfer);
720 }
721
722
723 /* Gladly, rendering to a MANAGED surface is not permitted, so we will
724 * never have to do the reverse, i.e. download the surface.
725 */
726 HRESULT
NineSurface9_UploadSelf(struct NineSurface9 * This,const struct pipe_box * damaged)727 NineSurface9_UploadSelf( struct NineSurface9 *This,
728 const struct pipe_box *damaged )
729 {
730 struct pipe_resource *res = This->base.resource;
731 struct pipe_box box;
732
733 DBG("This=%p damaged=%p\n", This, damaged);
734
735 assert(This->base.pool == D3DPOOL_MANAGED);
736
737 if (damaged) {
738 box = *damaged;
739 box.z = This->layer;
740 box.depth = 1;
741 } else {
742 box.x = 0;
743 box.y = 0;
744 box.z = This->layer;
745 box.width = This->desc.Width;
746 box.height = This->desc.Height;
747 box.depth = 1;
748 }
749
750 nine_context_box_upload(This->base.base.device,
751 &This->pending_uploads_counter,
752 (struct NineUnknown *)This,
753 res,
754 This->level,
755 &box,
756 res->format,
757 This->data, This->stride,
758 0, /* depth = 1 */
759 &box);
760
761 return D3D_OK;
762 }
763
764 /* Currently nine_context uses the NineSurface9
765 * fields when it is render target. Any modification requires
766 * pending commands with the surface to be executed. If the bind
767 * count is 0, there is no pending commands. */
768 #define PROCESS_IF_BOUND(surf) \
769 if (surf->base.base.bind) \
770 nine_csmt_process(surf->base.base.device);
771
772 void
NineSurface9_SetResource(struct NineSurface9 * This,struct pipe_resource * resource,unsigned level)773 NineSurface9_SetResource( struct NineSurface9 *This,
774 struct pipe_resource *resource, unsigned level )
775 {
776 /* No need to call PROCESS_IF_BOUND, because SetResource is used only
777 * for MANAGED textures, and they are not render targets. */
778 assert(This->base.pool == D3DPOOL_MANAGED);
779 This->level = level;
780 pipe_resource_reference(&This->base.resource, resource);
781 }
782
783 void
NineSurface9_SetMultiSampleType(struct NineSurface9 * This,D3DMULTISAMPLE_TYPE mst)784 NineSurface9_SetMultiSampleType( struct NineSurface9 *This,
785 D3DMULTISAMPLE_TYPE mst )
786 {
787 PROCESS_IF_BOUND(This);
788 This->desc.MultiSampleType = mst;
789 }
790
791 void
NineSurface9_SetResourceResize(struct NineSurface9 * This,struct pipe_resource * resource)792 NineSurface9_SetResourceResize( struct NineSurface9 *This,
793 struct pipe_resource *resource )
794 {
795 assert(This->level == 0 && This->level_actual == 0);
796 assert(!This->lock_count);
797 assert(This->desc.Pool == D3DPOOL_DEFAULT);
798 assert(!This->texture);
799
800 PROCESS_IF_BOUND(This);
801 pipe_resource_reference(&This->base.resource, resource);
802
803 This->desc.Width = This->base.info.width0 = resource->width0;
804 This->desc.Height = This->base.info.height0 = resource->height0;
805 This->base.info.nr_samples = resource->nr_samples;
806
807 This->stride = nine_format_get_stride(This->base.info.format,
808 This->desc.Width);
809
810 pipe_surface_reference(&This->surface[0], NULL);
811 pipe_surface_reference(&This->surface[1], NULL);
812 if (resource)
813 NineSurface9_CreatePipeSurfaces(This);
814 }
815
816
817 static const GUID *NineSurface9_IIDs[] = {
818 &IID_IDirect3DSurface9,
819 &IID_IDirect3DResource9,
820 &IID_IUnknown,
821 NULL
822 };
823
824 HRESULT
NineSurface9_new(struct NineDevice9 * pDevice,struct NineUnknown * pContainer,struct pipe_resource * pResource,void * user_buffer,uint8_t TextureType,unsigned Level,unsigned Layer,D3DSURFACE_DESC * pDesc,struct NineSurface9 ** ppOut)825 NineSurface9_new( struct NineDevice9 *pDevice,
826 struct NineUnknown *pContainer,
827 struct pipe_resource *pResource,
828 void *user_buffer,
829 uint8_t TextureType,
830 unsigned Level,
831 unsigned Layer,
832 D3DSURFACE_DESC *pDesc,
833 struct NineSurface9 **ppOut )
834 {
835 NINE_DEVICE_CHILD_NEW(Surface9, ppOut, pDevice, /* args */
836 pContainer, pResource, user_buffer,
837 TextureType, Level, Layer, pDesc);
838 }
839