VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Wine/wined3d/surface.c@ 41818

Last change on this file since 41818 was 41109, checked in by vboxsync, 13 years ago

crOpenGL,wined3d,wddm: second part of fixing resource leakage, basics for cr commands submission from r0 miniport driver (for r0 visible region reporting, WPF 3D rendering fixes w/o Aero, etc.)

  • Property svn:eol-style set to native
File size: 213.2 KB
Line 
1/*
2 * IWineD3DSurface Implementation
3 *
4 * Copyright 1998 Lionel Ulmer
5 * Copyright 2000-2001 TransGaming Technologies Inc.
6 * Copyright 2002-2005 Jason Edmeades
7 * Copyright 2002-2003 Raphael Junqueira
8 * Copyright 2004 Christian Costa
9 * Copyright 2005 Oliver Stieber
10 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
11 * Copyright 2007-2008 Henri Verbeet
12 * Copyright 2006-2008 Roderick Colenbrander
13 * Copyright 2009 Henri Verbeet for CodeWeavers
14 *
15 * This library is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU Lesser General Public
17 * License as published by the Free Software Foundation; either
18 * version 2.1 of the License, or (at your option) any later version.
19 *
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
24 *
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 */
29
30/*
31 * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
32 * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
33 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
34 * a choice of LGPL license versions is made available with the language indicating
35 * that LGPLv2 or any later version may be used, or where a choice of which version
36 * of the LGPL is applied is otherwise unspecified.
37 */
38
39#include "config.h"
40#include "wine/port.h"
41#include "wined3d_private.h"
42
43WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
44WINE_DECLARE_DEBUG_CHANNEL(d3d);
45
46#define GLINFO_LOCATION (*gl_info)
47
48#ifdef VBOX_WITH_WDDM
49void surface_shrc_lock_surf(IWineD3DSurfaceImpl *This)
50{
51 VBOXSHRC_LOCK(This);
52}
53
54void surface_shrc_unlock_surf(IWineD3DSurfaceImpl *This)
55{
56 VBOXSHRC_UNLOCK(This);
57 if (VBOXSHRC_IS_LOCKED(This))
58 return;
59
60 /* perform data->texture synchronization */
61 IWineD3DSurface_LoadLocation((IWineD3DSurface*)This, SFLAG_INTEXTURE, NULL);
62}
63
64void surface_shrc_lock(IWineD3DSurfaceImpl *This)
65{
66 if (!VBOXSHRC_IS_SHARED(This))
67 return;
68
69 surface_shrc_lock_surf(This);
70}
71
72void surface_shrc_unlock(IWineD3DSurfaceImpl *This)
73{
74 if (!VBOXSHRC_IS_SHARED(This))
75 return;
76 surface_shrc_unlock_surf(This);
77}
78#endif
79
80static void surface_cleanup(IWineD3DSurfaceImpl *This)
81{
82 IWineD3DDeviceImpl *device = This->resource.device;
83 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
84 struct wined3d_context *context = NULL;
85 renderbuffer_entry_t *entry, *entry2;
86
87 TRACE("(%p) : Cleaning up.\n", This);
88
89 /* Need a context to destroy the texture. Use the currently active render
90 * target, but only if the primary render target exists. Otherwise
91 * lastActiveRenderTarget is garbage. When destroying the primary render
92 * target, Uninit3D() will activate a context before doing anything. */
93 if (device->render_targets && device->render_targets[0])
94 {
95 context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
96 }
97
98 ENTER_GL();
99
100 if (This->texture_name)
101 {
102 /* Release the OpenGL texture. */
103 TRACE("Deleting texture %u.\n", This->texture_name);
104 texture_gl_delete(This, This->texture_name);
105 }
106
107 if (This->Flags & SFLAG_PBO)
108 {
109 /* Delete the PBO. */
110 GL_EXTCALL(glDeleteBuffersARB(1, &This->pbo));
111 }
112
113 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &This->renderbuffers, renderbuffer_entry_t, entry)
114 {
115 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
116 HeapFree(GetProcessHeap(), 0, entry);
117 }
118
119 LEAVE_GL();
120
121 if (This->Flags & SFLAG_DIBSECTION)
122 {
123 /* Release the DC. */
124 SelectObject(This->hDC, This->dib.holdbitmap);
125 DeleteDC(This->hDC);
126 /* Release the DIB section. */
127 DeleteObject(This->dib.DIBsection);
128 This->dib.bitmap_data = NULL;
129 This->resource.allocatedMemory = NULL;
130 }
131
132 if (This->Flags & SFLAG_USERPTR) IWineD3DSurface_SetMem((IWineD3DSurface *)This, NULL);
133 if (This->overlay_dest) list_remove(&This->overlay_entry);
134
135 HeapFree(GetProcessHeap(), 0, This->palette9);
136
137 resource_cleanup((IWineD3DResource *)This);
138
139 if (context) context_release(context);
140}
141
142UINT surface_calculate_size(const struct wined3d_format_desc *format_desc, UINT alignment, UINT width, UINT height)
143{
144 UINT size;
145
146 if (format_desc->format == WINED3DFMT_UNKNOWN)
147 {
148 size = 0;
149 }
150 else if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
151 {
152 UINT row_block_count = (width + format_desc->block_width - 1) / format_desc->block_width;
153 UINT row_count = (height + format_desc->block_height - 1) / format_desc->block_height;
154 size = row_count * row_block_count * format_desc->block_byte_count;
155 }
156 else
157 {
158 /* The pitch is a multiple of 4 bytes. */
159 size = height * (((width * format_desc->byte_count) + alignment - 1) & ~(alignment - 1));
160 }
161
162 if (format_desc->heightscale != 0.0f) size *= format_desc->heightscale;
163
164 return size;
165}
166
167struct blt_info
168{
169 GLenum binding;
170 GLenum bind_target;
171 enum tex_types tex_type;
172 GLfloat coords[4][3];
173};
174
175struct float_rect
176{
177 float l;
178 float t;
179 float r;
180 float b;
181};
182
183static inline void cube_coords_float(const RECT *r, UINT w, UINT h, struct float_rect *f)
184{
185 f->l = ((r->left * 2.0f) / w) - 1.0f;
186 f->t = ((r->top * 2.0f) / h) - 1.0f;
187 f->r = ((r->right * 2.0f) / w) - 1.0f;
188 f->b = ((r->bottom * 2.0f) / h) - 1.0f;
189}
190
191static void surface_get_blt_info(GLenum target, const RECT *rect_in, GLsizei w, GLsizei h, struct blt_info *info)
192{
193 GLfloat (*coords)[3] = info->coords;
194 RECT rect;
195 struct float_rect f;
196
197 if (rect_in)
198 rect = *rect_in;
199 else
200 {
201 rect.left = 0;
202 rect.top = h;
203 rect.right = w;
204 rect.bottom = 0;
205 }
206
207 switch (target)
208 {
209 default:
210 FIXME("Unsupported texture target %#x\n", target);
211 /* Fall back to GL_TEXTURE_2D */
212 case GL_TEXTURE_2D:
213 info->binding = GL_TEXTURE_BINDING_2D;
214 info->bind_target = GL_TEXTURE_2D;
215 info->tex_type = tex_2d;
216 coords[0][0] = (float)rect.left / w;
217 coords[0][1] = (float)rect.top / h;
218 coords[0][2] = 0.0f;
219
220 coords[1][0] = (float)rect.right / w;
221 coords[1][1] = (float)rect.top / h;
222 coords[1][2] = 0.0f;
223
224 coords[2][0] = (float)rect.left / w;
225 coords[2][1] = (float)rect.bottom / h;
226 coords[2][2] = 0.0f;
227
228 coords[3][0] = (float)rect.right / w;
229 coords[3][1] = (float)rect.bottom / h;
230 coords[3][2] = 0.0f;
231 break;
232
233 case GL_TEXTURE_RECTANGLE_ARB:
234 info->binding = GL_TEXTURE_BINDING_RECTANGLE_ARB;
235 info->bind_target = GL_TEXTURE_RECTANGLE_ARB;
236 info->tex_type = tex_rect;
237 coords[0][0] = rect.left; coords[0][1] = rect.top; coords[0][2] = 0.0f;
238 coords[1][0] = rect.right; coords[1][1] = rect.top; coords[1][2] = 0.0f;
239 coords[2][0] = rect.left; coords[2][1] = rect.bottom; coords[2][2] = 0.0f;
240 coords[3][0] = rect.right; coords[3][1] = rect.bottom; coords[3][2] = 0.0f;
241 break;
242
243 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
244 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
245 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
246 info->tex_type = tex_cube;
247 cube_coords_float(&rect, w, h, &f);
248
249 coords[0][0] = 1.0f; coords[0][1] = -f.t; coords[0][2] = -f.l;
250 coords[1][0] = 1.0f; coords[1][1] = -f.t; coords[1][2] = -f.r;
251 coords[2][0] = 1.0f; coords[2][1] = -f.b; coords[2][2] = -f.l;
252 coords[3][0] = 1.0f; coords[3][1] = -f.b; coords[3][2] = -f.r;
253 break;
254
255 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
256 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
257 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
258 info->tex_type = tex_cube;
259 cube_coords_float(&rect, w, h, &f);
260
261 coords[0][0] = -1.0f; coords[0][1] = -f.t; coords[0][2] = f.l;
262 coords[1][0] = -1.0f; coords[1][1] = -f.t; coords[1][2] = f.r;
263 coords[2][0] = -1.0f; coords[2][1] = -f.b; coords[2][2] = f.l;
264 coords[3][0] = -1.0f; coords[3][1] = -f.b; coords[3][2] = f.r;
265 break;
266
267 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
268 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
269 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
270 info->tex_type = tex_cube;
271 cube_coords_float(&rect, w, h, &f);
272
273 coords[0][0] = f.l; coords[0][1] = 1.0f; coords[0][2] = f.t;
274 coords[1][0] = f.r; coords[1][1] = 1.0f; coords[1][2] = f.t;
275 coords[2][0] = f.l; coords[2][1] = 1.0f; coords[2][2] = f.b;
276 coords[3][0] = f.r; coords[3][1] = 1.0f; coords[3][2] = f.b;
277 break;
278
279 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
280 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
281 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
282 info->tex_type = tex_cube;
283 cube_coords_float(&rect, w, h, &f);
284
285 coords[0][0] = f.l; coords[0][1] = -1.0f; coords[0][2] = -f.t;
286 coords[1][0] = f.r; coords[1][1] = -1.0f; coords[1][2] = -f.t;
287 coords[2][0] = f.l; coords[2][1] = -1.0f; coords[2][2] = -f.b;
288 coords[3][0] = f.r; coords[3][1] = -1.0f; coords[3][2] = -f.b;
289 break;
290
291 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
292 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
293 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
294 info->tex_type = tex_cube;
295 cube_coords_float(&rect, w, h, &f);
296
297 coords[0][0] = f.l; coords[0][1] = -f.t; coords[0][2] = 1.0f;
298 coords[1][0] = f.r; coords[1][1] = -f.t; coords[1][2] = 1.0f;
299 coords[2][0] = f.l; coords[2][1] = -f.b; coords[2][2] = 1.0f;
300 coords[3][0] = f.r; coords[3][1] = -f.b; coords[3][2] = 1.0f;
301 break;
302
303 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
304 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
305 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
306 info->tex_type = tex_cube;
307 cube_coords_float(&rect, w, h, &f);
308
309 coords[0][0] = -f.l; coords[0][1] = -f.t; coords[0][2] = -1.0f;
310 coords[1][0] = -f.r; coords[1][1] = -f.t; coords[1][2] = -1.0f;
311 coords[2][0] = -f.l; coords[2][1] = -f.b; coords[2][2] = -1.0f;
312 coords[3][0] = -f.r; coords[3][1] = -f.b; coords[3][2] = -1.0f;
313 break;
314 }
315}
316
317static inline void surface_get_rect(IWineD3DSurfaceImpl *This, const RECT *rect_in, RECT *rect_out)
318{
319 if (rect_in)
320 *rect_out = *rect_in;
321 else
322 {
323 rect_out->left = 0;
324 rect_out->top = 0;
325 rect_out->right = This->currentDesc.Width;
326 rect_out->bottom = This->currentDesc.Height;
327 }
328}
329
330/* GL locking and context activation is done by the caller */
331void draw_textured_quad(IWineD3DSurfaceImpl *src_surface, const RECT *src_rect, const RECT *dst_rect, WINED3DTEXTUREFILTERTYPE Filter)
332{
333 IWineD3DBaseTextureImpl *texture;
334 struct blt_info info;
335
336 surface_get_blt_info(src_surface->texture_target, src_rect, src_surface->pow2Width, src_surface->pow2Height, &info);
337
338 glEnable(info.bind_target);
339 checkGLcall("glEnable(bind_target)");
340
341 /* Bind the texture */
342 glBindTexture(info.bind_target, src_surface->texture_name);
343 checkGLcall("glBindTexture");
344
345 /* Filtering for StretchRect */
346 glTexParameteri(info.bind_target, GL_TEXTURE_MAG_FILTER,
347 wined3d_gl_mag_filter(magLookup, Filter));
348 checkGLcall("glTexParameteri");
349 glTexParameteri(info.bind_target, GL_TEXTURE_MIN_FILTER,
350 wined3d_gl_min_mip_filter(minMipLookup, Filter, WINED3DTEXF_NONE));
351 checkGLcall("glTexParameteri");
352 glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
353 glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
354 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
355 checkGLcall("glTexEnvi");
356
357 /* Draw a quad */
358 glBegin(GL_TRIANGLE_STRIP);
359 glTexCoord3fv(info.coords[0]);
360 glVertex2i(dst_rect->left, dst_rect->top);
361
362 glTexCoord3fv(info.coords[1]);
363 glVertex2i(dst_rect->right, dst_rect->top);
364
365 glTexCoord3fv(info.coords[2]);
366 glVertex2i(dst_rect->left, dst_rect->bottom);
367
368 glTexCoord3fv(info.coords[3]);
369 glVertex2i(dst_rect->right, dst_rect->bottom);
370 glEnd();
371
372 /* Unbind the texture */
373 glBindTexture(info.bind_target, 0);
374 checkGLcall("glBindTexture(info->bind_target, 0)");
375
376 /* We changed the filtering settings on the texture. Inform the
377 * container about this to get the filters reset properly next draw. */
378 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)src_surface, &IID_IWineD3DBaseTexture, (void **)&texture)))
379 {
380 texture->baseTexture.texture_rgb.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
381 texture->baseTexture.texture_rgb.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
382 texture->baseTexture.texture_rgb.states[WINED3DTEXSTA_MIPFILTER] = WINED3DTEXF_NONE;
383 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture);
384 }
385}
386
387HRESULT surface_init(IWineD3DSurfaceImpl *surface, WINED3DSURFTYPE surface_type, UINT alignment,
388 UINT width, UINT height, UINT level, BOOL lockable, BOOL discard, WINED3DMULTISAMPLE_TYPE multisample_type,
389 UINT multisample_quality, IWineD3DDeviceImpl *device, DWORD usage, WINED3DFORMAT format,
390 WINED3DPOOL pool, IUnknown *parent, const struct wined3d_parent_ops *parent_ops
391#ifdef VBOX_WITH_WDDM
392 , HANDLE *shared_handle
393 , void *pvClientMem
394#endif
395 )
396{
397 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
398 const struct wined3d_format_desc *format_desc = getFormatDescEntry(format, gl_info);
399 void (*cleanup)(IWineD3DSurfaceImpl *This);
400 unsigned int resource_size;
401 HRESULT hr;
402
403 if (multisample_quality > 0)
404 {
405 FIXME("multisample_quality set to %u, substituting 0\n", multisample_quality);
406 multisample_quality = 0;
407 }
408
409 /* FIXME: Check that the format is supported by the device. */
410
411 resource_size = surface_calculate_size(format_desc, alignment, width, height);
412
413 /* Look at the implementation and set the correct Vtable. */
414 switch (surface_type)
415 {
416 case SURFACE_OPENGL:
417 surface->lpVtbl = &IWineD3DSurface_Vtbl;
418 cleanup = surface_cleanup;
419 break;
420
421 case SURFACE_GDI:
422 surface->lpVtbl = &IWineGDISurface_Vtbl;
423 cleanup = surface_gdi_cleanup;
424 break;
425
426 default:
427 ERR("Requested unknown surface implementation %#x.\n", surface_type);
428 return WINED3DERR_INVALIDCALL;
429 }
430
431 hr = resource_init((IWineD3DResource *)surface, WINED3DRTYPE_SURFACE,
432 device, resource_size, usage, format_desc, pool, parent, parent_ops
433#ifdef VBOX_WITH_WDDM
434 , shared_handle
435 , pvClientMem
436#endif
437 );
438 if (FAILED(hr))
439 {
440 WARN("Failed to initialize resource, returning %#x.\n", hr);
441 return hr;
442 }
443
444#ifdef VBOX_WITH_WDDM
445 /* this will be a nop for the non-shared resource,
446 * for the shared resource this will ensure the surface is initialized properly */
447 surface_shrc_lock(surface);
448#endif
449
450 /* "Standalone" surface. */
451 IWineD3DSurface_SetContainer((IWineD3DSurface *)surface, NULL);
452
453 surface->currentDesc.Width = width;
454 surface->currentDesc.Height = height;
455 surface->currentDesc.MultiSampleType = multisample_type;
456 surface->currentDesc.MultiSampleQuality = multisample_quality;
457 surface->texture_level = level;
458 list_init(&surface->overlays);
459
460 /* Flags */
461 surface->Flags = SFLAG_NORMCOORD; /* Default to normalized coords. */
462#ifdef VBOX_WITH_WDDM
463 if (pool == WINED3DPOOL_SYSTEMMEM && pvClientMem) surface->Flags |= SFLAG_CLIENTMEM;
464#endif
465 if (discard) surface->Flags |= SFLAG_DISCARD;
466 if (lockable || format == WINED3DFMT_D16_LOCKABLE) surface->Flags |= SFLAG_LOCKABLE;
467
468 /* Quick lockable sanity check.
469 * TODO: remove this after surfaces, usage and lockability have been debugged properly
470 * this function is too deep to need to care about things like this.
471 * Levels need to be checked too, since they all affect what can be done. */
472 switch (pool)
473 {
474 case WINED3DPOOL_SCRATCH:
475 if(!lockable)
476 {
477 FIXME("Called with a pool of SCRATCH and a lockable of FALSE "
478 "which are mutually exclusive, setting lockable to TRUE.\n");
479 lockable = TRUE;
480 }
481 break;
482
483 case WINED3DPOOL_SYSTEMMEM:
484 if (!lockable)
485 FIXME("Called with a pool of SYSTEMMEM and a lockable of FALSE, this is acceptable but unexpected.\n");
486 break;
487
488 case WINED3DPOOL_MANAGED:
489 if (usage & WINED3DUSAGE_DYNAMIC)
490 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
491 break;
492
493 case WINED3DPOOL_DEFAULT:
494 if (lockable && !(usage & (WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
495 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
496 break;
497
498 default:
499 FIXME("Unknown pool %#x.\n", pool);
500 break;
501 };
502
503 if (usage & WINED3DUSAGE_RENDERTARGET && pool != WINED3DPOOL_DEFAULT)
504 {
505 FIXME("Trying to create a render target that isn't in the default pool.\n");
506 }
507
508 /* Mark the texture as dirty so that it gets loaded first time around. */
509 surface_add_dirty_rect((IWineD3DSurface *)surface, NULL);
510 list_init(&surface->renderbuffers);
511
512 TRACE("surface %p, memory %p, size %u\n", surface, surface->resource.allocatedMemory, surface->resource.size);
513
514 /* Call the private setup routine */
515 hr = IWineD3DSurface_PrivateSetup((IWineD3DSurface *)surface);
516 if (FAILED(hr))
517 {
518 ERR("Private setup failed, returning %#x\n", hr);
519 cleanup(surface);
520 return hr;
521 }
522
523#ifdef VBOX_WITH_WDDM
524 if (VBOXSHRC_IS_SHARED(surface))
525 {
526 struct wined3d_context * context;
527 Assert(shared_handle);
528 if (!VBOXSHRC_IS_SHARED_OPENED(surface))
529 {
530 surface_shrc_unlock(surface);
531 Assert(!(*shared_handle));
532 *shared_handle = VBOXSHRC_GET_SHAREHANDLE(surface);
533 }
534 else
535 {
536 VBOXSHRC_UNLOCK(surface);
537 Assert(!VBOXSHRC_IS_LOCKED(surface));
538#ifdef DEBUG_misha
539 ERR("test this!");
540#endif
541 surface_setup_location_onopen(surface);
542 Assert(*shared_handle);
543 Assert(*shared_handle == VBOXSHRC_GET_SHAREHANDLE(surface));
544 }
545
546 Assert(!device->isInDraw);
547
548 /* flush to ensure the texture is allocated/referenced before it is used/released by another
549 * process opening/creating it */
550 context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
551 if (context->valid)
552 {
553 wglFlush();
554 }
555 else
556 {
557 ERR("invalid context!");
558 }
559 context_release(context);
560 }
561 else
562 {
563 Assert(!shared_handle);
564 }
565
566 surface->presentSwapchain = NULL;
567#endif
568
569 return hr;
570}
571
572static void surface_force_reload(IWineD3DSurface *iface)
573{
574 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
575
576 This->Flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
577}
578
579void surface_set_texture_name(IWineD3DSurface *iface, GLuint new_name, BOOL srgb)
580{
581 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
582 GLuint *name;
583 DWORD flag;
584
585 if(srgb)
586 {
587 name = &This->texture_name_srgb;
588 flag = SFLAG_INSRGBTEX;
589 }
590 else
591 {
592 name = &This->texture_name;
593 flag = SFLAG_INTEXTURE;
594 }
595
596 TRACE("(%p) : setting texture name %u\n", This, new_name);
597
598 if (!*name && new_name)
599 {
600 BOOL fPersistent = FALSE;
601 /* FIXME: We shouldn't need to remove SFLAG_INTEXTURE if the
602 * surface has no texture name yet. See if we can get rid of this. */
603 if (This->Flags & flag)
604 ERR("Surface has SFLAG_INTEXTURE set, but no texture name\n");
605#ifdef VBOX_WITH_WDDM
606 if (VBOXSHRC_IS_SHARED_OPENED(This))
607 {
608 fPersistent = TRUE;
609 }
610#endif
611 IWineD3DSurface_ModifyLocation(iface, flag, fPersistent);
612 }
613
614#ifdef VBOX_WITH_WDDM
615 if (VBOXSHRC_IS_SHARED(This))
616 {
617 Assert(VBOXSHRC_GET_SHAREHANDLE(This) == NULL
618 || (GLuint)VBOXSHRC_GET_SHAREHANDLE(This) == new_name
619 || new_name == 0 /* on cleanup */);
620 VBOXSHRC_SET_SHAREHANDLE(This, new_name);
621 }
622#endif
623 *name = new_name;
624 surface_force_reload(iface);
625}
626
627void surface_set_texture_target(IWineD3DSurface *iface, GLenum target)
628{
629 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
630
631 TRACE("(%p) : setting target %#x\n", This, target);
632
633 if (This->texture_target != target)
634 {
635 if (target == GL_TEXTURE_RECTANGLE_ARB)
636 {
637 This->Flags &= ~SFLAG_NORMCOORD;
638 }
639 else if (This->texture_target == GL_TEXTURE_RECTANGLE_ARB)
640 {
641 This->Flags |= SFLAG_NORMCOORD;
642 }
643 }
644 This->texture_target = target;
645 surface_force_reload(iface);
646}
647
648/* Context activation is done by the caller. */
649static void surface_bind_and_dirtify(IWineD3DSurfaceImpl *This, BOOL srgb) {
650 DWORD active_sampler;
651
652 /* We don't need a specific texture unit, but after binding the texture the current unit is dirty.
653 * Read the unit back instead of switching to 0, this avoids messing around with the state manager's
654 * gl states. The current texture unit should always be a valid one.
655 *
656 * To be more specific, this is tricky because we can implicitly be called
657 * from sampler() in state.c. This means we can't touch anything other than
658 * whatever happens to be the currently active texture, or we would risk
659 * marking already applied sampler states dirty again.
660 *
661 * TODO: Track the current active texture per GL context instead of using glGet
662 */
663 GLint active_texture=GL_TEXTURE0_ARB;
664 ENTER_GL();
665 glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
666 LEAVE_GL();
667 active_sampler = This->resource.device->rev_tex_unit_map[active_texture - GL_TEXTURE0_ARB];
668
669 if (active_sampler != WINED3D_UNMAPPED_STAGE)
670 {
671 IWineD3DDeviceImpl_MarkStateDirty(This->resource.device, STATE_SAMPLER(active_sampler));
672 }
673 IWineD3DSurface_BindTexture((IWineD3DSurface *)This, srgb);
674}
675
676
677/* This function checks if the primary render target uses the 8bit paletted format. */
678static BOOL primary_render_target_is_p8(IWineD3DDeviceImpl *device)
679{
680 if (device->render_targets && device->render_targets[0]) {
681 IWineD3DSurfaceImpl* render_target = (IWineD3DSurfaceImpl*)device->render_targets[0];
682 if ((render_target->resource.usage & WINED3DUSAGE_RENDERTARGET)
683 && (render_target->resource.format_desc->format == WINED3DFMT_P8_UINT))
684 return TRUE;
685 }
686 return FALSE;
687}
688
689/* This call just downloads data, the caller is responsible for binding the
690 * correct texture. */
691/* Context activation is done by the caller. */
692static void surface_download_data(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info)
693{
694 const struct wined3d_format_desc *format_desc = This->resource.format_desc;
695
696 /* Only support read back of converted P8 surfaces */
697 if (This->Flags & SFLAG_CONVERTED && format_desc->format != WINED3DFMT_P8_UINT)
698 {
699 FIXME("Read back converted textures unsupported, format=%s\n", debug_d3dformat(format_desc->format));
700 return;
701 }
702
703 ENTER_GL();
704
705 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
706 {
707 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
708 This, This->texture_level, format_desc->glFormat, format_desc->glType,
709 This->resource.allocatedMemory);
710
711 if (This->Flags & SFLAG_PBO)
712 {
713 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
714 checkGLcall("glBindBufferARB");
715 GL_EXTCALL(glGetCompressedTexImageARB(This->texture_target, This->texture_level, NULL));
716 checkGLcall("glGetCompressedTexImageARB");
717 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
718 checkGLcall("glBindBufferARB");
719 }
720 else
721 {
722 GL_EXTCALL(glGetCompressedTexImageARB(This->texture_target,
723 This->texture_level, This->resource.allocatedMemory));
724 checkGLcall("glGetCompressedTexImageARB");
725 }
726
727 LEAVE_GL();
728 } else {
729 void *mem;
730 GLenum format = format_desc->glFormat;
731 GLenum type = format_desc->glType;
732 int src_pitch = 0;
733 int dst_pitch = 0;
734
735 /* In case of P8 the index is stored in the alpha component if the primary render target uses P8 */
736 if (format_desc->format == WINED3DFMT_P8_UINT && primary_render_target_is_p8(This->resource.device))
737 {
738 format = GL_ALPHA;
739 type = GL_UNSIGNED_BYTE;
740 }
741
742 if (This->Flags & SFLAG_NONPOW2) {
743 unsigned char alignment = This->resource.device->surface_alignment;
744 src_pitch = format_desc->byte_count * This->pow2Width;
745 dst_pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This);
746 src_pitch = (src_pitch + alignment - 1) & ~(alignment - 1);
747 mem = HeapAlloc(GetProcessHeap(), 0, src_pitch * This->pow2Height);
748 } else {
749 mem = This->resource.allocatedMemory;
750 }
751
752 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
753 This, This->texture_level, format, type, mem);
754
755 if(This->Flags & SFLAG_PBO) {
756 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
757 checkGLcall("glBindBufferARB");
758
759 glGetTexImage(This->texture_target, This->texture_level, format, type, NULL);
760 checkGLcall("glGetTexImage");
761
762 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
763 checkGLcall("glBindBufferARB");
764 } else {
765 glGetTexImage(This->texture_target, This->texture_level, format, type, mem);
766 checkGLcall("glGetTexImage");
767 }
768 LEAVE_GL();
769
770 if (This->Flags & SFLAG_NONPOW2) {
771 const BYTE *src_data;
772 BYTE *dst_data;
773 UINT y;
774 /*
775 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
776 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
777 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
778 *
779 * We're doing this...
780 *
781 * instead of boxing the texture :
782 * |<-texture width ->| -->pow2width| /\
783 * |111111111111111111| | |
784 * |222 Texture 222222| boxed empty | texture height
785 * |3333 Data 33333333| | |
786 * |444444444444444444| | \/
787 * ----------------------------------- |
788 * | boxed empty | boxed empty | pow2height
789 * | | | \/
790 * -----------------------------------
791 *
792 *
793 * we're repacking the data to the expected texture width
794 *
795 * |<-texture width ->| -->pow2width| /\
796 * |111111111111111111222222222222222| |
797 * |222333333333333333333444444444444| texture height
798 * |444444 | |
799 * | | \/
800 * | | |
801 * | empty | pow2height
802 * | | \/
803 * -----------------------------------
804 *
805 * == is the same as
806 *
807 * |<-texture width ->| /\
808 * |111111111111111111|
809 * |222222222222222222|texture height
810 * |333333333333333333|
811 * |444444444444444444| \/
812 * --------------------
813 *
814 * this also means that any references to allocatedMemory should work with the data as if were a
815 * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
816 *
817 * internally the texture is still stored in a boxed format so any references to textureName will
818 * get a boxed texture with width pow2width and not a texture of width currentDesc.Width.
819 *
820 * Performance should not be an issue, because applications normally do not lock the surfaces when
821 * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
822 * and doesn't have to be re-read.
823 */
824 src_data = mem;
825 dst_data = This->resource.allocatedMemory;
826 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, src_pitch, dst_pitch);
827 for (y = 1 ; y < This->currentDesc.Height; y++) {
828 /* skip the first row */
829 src_data += src_pitch;
830 dst_data += dst_pitch;
831 memcpy(dst_data, src_data, dst_pitch);
832 }
833
834 HeapFree(GetProcessHeap(), 0, mem);
835 }
836 }
837
838 /* Surface has now been downloaded */
839 This->Flags |= SFLAG_INSYSMEM;
840}
841
842/* This call just uploads data, the caller is responsible for binding the
843 * correct texture. */
844/* Context activation is done by the caller. */
845static void surface_upload_data(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info,
846 const struct wined3d_format_desc *format_desc, BOOL srgb, const GLvoid *data)
847{
848 GLsizei width = This->currentDesc.Width;
849 GLsizei height = This->currentDesc.Height;
850 GLenum internal;
851
852 if (srgb)
853 {
854 internal = format_desc->glGammaInternal;
855 }
856 else if (This->resource.usage & WINED3DUSAGE_RENDERTARGET
857 && surface_is_offscreen((IWineD3DSurface *)This))
858 {
859 internal = format_desc->rtInternal;
860 }
861 else
862 {
863 internal = format_desc->glInternal;
864 }
865
866 TRACE("This %p, internal %#x, width %d, height %d, format %#x, type %#x, data %p.\n",
867 This, internal, width, height, format_desc->glFormat, format_desc->glType, data);
868 TRACE("target %#x, level %u, resource size %u.\n",
869 This->texture_target, This->texture_level, This->resource.size);
870
871 if (format_desc->heightscale != 1.0f && format_desc->heightscale != 0.0f) height *= format_desc->heightscale;
872
873 ENTER_GL();
874
875 if (This->Flags & SFLAG_PBO)
876 {
877 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
878 checkGLcall("glBindBufferARB");
879
880 TRACE("(%p) pbo: %#x, data: %p.\n", This, This->pbo, data);
881 data = NULL;
882 }
883
884 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
885 {
886 TRACE("Calling glCompressedTexSubImage2DARB.\n");
887
888 GL_EXTCALL(glCompressedTexSubImage2DARB(This->texture_target, This->texture_level,
889 0, 0, width, height, internal, This->resource.size, data));
890 checkGLcall("glCompressedTexSubImage2DARB");
891 }
892 else
893 {
894 TRACE("Calling glTexSubImage2D.\n");
895
896 glTexSubImage2D(This->texture_target, This->texture_level,
897 0, 0, width, height, format_desc->glFormat, format_desc->glType, data);
898 checkGLcall("glTexSubImage2D");
899 }
900
901 if (This->Flags & SFLAG_PBO)
902 {
903 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
904 checkGLcall("glBindBufferARB");
905 }
906
907 LEAVE_GL();
908
909 if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
910 {
911 IWineD3DDeviceImpl *device = This->resource.device;
912 unsigned int i;
913
914 for (i = 0; i < device->numContexts; ++i)
915 {
916 context_surface_update(device->contexts[i], This);
917 }
918 }
919}
920
921#ifdef VBOX_WITH_WDDM
922static void surface_upload_data_rect(IWineD3DSurfaceImpl *This, IWineD3DSurfaceImpl *Src, const struct wined3d_gl_info *gl_info,
923 const struct wined3d_format_desc *format_desc, BOOL srgb, const GLvoid *data, RECT *pRect)
924{
925 GLsizei width = pRect->right - pRect->left;
926 GLsizei height = pRect->bottom - pRect->top;
927 GLenum internal;
928
929 if (srgb)
930 {
931 internal = format_desc->glGammaInternal;
932 }
933 else if (This->resource.usage & WINED3DUSAGE_RENDERTARGET
934 && surface_is_offscreen((IWineD3DSurface *)This))
935 {
936 internal = format_desc->rtInternal;
937 }
938 else
939 {
940 internal = format_desc->glInternal;
941 }
942
943 TRACE("This %p, internal %#x, width %d, height %d, format %#x, type %#x, data %p.\n",
944 This, internal, width, height, format_desc->glFormat, format_desc->glType, data);
945 TRACE("target %#x, level %u, resource size %u.\n",
946 This->texture_target, This->texture_level, This->resource.size);
947
948 if (format_desc->heightscale != 1.0f && format_desc->heightscale != 0.0f) height *= format_desc->heightscale;
949
950 ENTER_GL();
951
952 if (Src->Flags & SFLAG_PBO)
953 {
954 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, Src->pbo));
955 checkGLcall("glBindBufferARB");
956
957 TRACE("(%p) pbo: %#x, data: %p.\n", Src, Src->pbo, data);
958 /* the data should contain a zero-based offset */
959 }
960
961 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
962 {
963 TRACE("Calling glCompressedTexSubImage2DARB.\n");
964
965 GL_EXTCALL(glCompressedTexSubImage2DARB(This->texture_target, This->texture_level,
966 pRect->left, pRect->top, width, height, internal, This->resource.size, data));
967 checkGLcall("glCompressedTexSubImage2DARB");
968 }
969 else
970 {
971 TRACE("Calling glTexSubImage2D.\n");
972
973 glTexSubImage2D(This->texture_target, This->texture_level,
974 pRect->left, pRect->top, width, height, format_desc->glFormat, format_desc->glType, data);
975 checkGLcall("glTexSubImage2D");
976 }
977
978 if (Src->Flags & SFLAG_PBO)
979 {
980 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
981 checkGLcall("glBindBufferARB");
982 }
983
984 LEAVE_GL();
985
986 if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
987 {
988 IWineD3DDeviceImpl *device = This->resource.device;
989 unsigned int i;
990
991 for (i = 0; i < device->numContexts; ++i)
992 {
993 context_surface_update(device->contexts[i], This);
994 }
995 }
996}
997#endif
998
999/* This call just allocates the texture, the caller is responsible for binding
1000 * the correct texture. */
1001/* Context activation is done by the caller. */
1002static void surface_allocate_surface(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info,
1003 const struct wined3d_format_desc *format_desc, BOOL srgb)
1004{
1005 BOOL enable_client_storage = FALSE;
1006 GLsizei width = This->pow2Width;
1007 GLsizei height = This->pow2Height;
1008 const BYTE *mem = NULL;
1009 GLenum internal;
1010
1011#ifdef VBOX_WITH_WDDM
1012 if (VBOXSHRC_IS_SHARED_OPENED(This))
1013 {
1014 ERR("trying to allocate shared openned resource!!, ignoring..\n");
1015 return;
1016 }
1017#endif
1018
1019 if (srgb)
1020 {
1021 internal = format_desc->glGammaInternal;
1022 }
1023 else if (This->resource.usage & WINED3DUSAGE_RENDERTARGET
1024 && surface_is_offscreen((IWineD3DSurface *)This))
1025 {
1026 internal = format_desc->rtInternal;
1027 }
1028 else
1029 {
1030 internal = format_desc->glInternal;
1031 }
1032
1033 if (format_desc->heightscale != 1.0f && format_desc->heightscale != 0.0f) height *= format_desc->heightscale;
1034
1035 TRACE("(%p) : Creating surface (target %#x) level %d, d3d format %s, internal format %#x, width %d, height %d, gl format %#x, gl type=%#x\n",
1036 This, This->texture_target, This->texture_level, debug_d3dformat(format_desc->format),
1037 internal, width, height, format_desc->glFormat, format_desc->glType);
1038
1039 ENTER_GL();
1040
1041 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1042 {
1043 if(This->Flags & (SFLAG_NONPOW2 | SFLAG_DIBSECTION | SFLAG_CONVERTED) || This->resource.allocatedMemory == NULL) {
1044 /* In some cases we want to disable client storage.
1045 * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
1046 * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
1047 * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
1048 * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively
1049 */
1050 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1051 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1052 This->Flags &= ~SFLAG_CLIENT;
1053 enable_client_storage = TRUE;
1054 } else {
1055 This->Flags |= SFLAG_CLIENT;
1056
1057 /* Point opengl to our allocated texture memory. Do not use resource.allocatedMemory here because
1058 * it might point into a pbo. Instead use heapMemory, but get the alignment right.
1059 */
1060 mem = (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
1061 }
1062 }
1063
1064 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED && mem)
1065 {
1066 GL_EXTCALL(glCompressedTexImage2DARB(This->texture_target, This->texture_level,
1067 internal, width, height, 0, This->resource.size, mem));
1068 }
1069 else
1070 {
1071 glTexImage2D(This->texture_target, This->texture_level,
1072 internal, width, height, 0, format_desc->glFormat, format_desc->glType, mem);
1073 checkGLcall("glTexImage2D");
1074 }
1075
1076 if(enable_client_storage) {
1077 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1078 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1079 }
1080 LEAVE_GL();
1081}
1082
1083/* In D3D the depth stencil dimensions have to be greater than or equal to the
1084 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
1085/* TODO: We should synchronize the renderbuffer's content with the texture's content. */
1086/* GL locking is done by the caller */
1087void surface_set_compatible_renderbuffer(IWineD3DSurface *iface, unsigned int width, unsigned int height) {
1088 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1089 const struct wined3d_gl_info *gl_info = &This->resource.device->adapter->gl_info;
1090 renderbuffer_entry_t *entry;
1091 GLuint renderbuffer = 0;
1092 unsigned int src_width, src_height;
1093
1094 src_width = This->pow2Width;
1095 src_height = This->pow2Height;
1096
1097 /* A depth stencil smaller than the render target is not valid */
1098 if (width > src_width || height > src_height) return;
1099
1100 /* Remove any renderbuffer set if the sizes match */
1101 if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]
1102 || (width == src_width && height == src_height))
1103 {
1104 This->current_renderbuffer = NULL;
1105 return;
1106 }
1107
1108 /* Look if we've already got a renderbuffer of the correct dimensions */
1109 LIST_FOR_EACH_ENTRY(entry, &This->renderbuffers, renderbuffer_entry_t, entry) {
1110 if (entry->width == width && entry->height == height) {
1111 renderbuffer = entry->id;
1112 This->current_renderbuffer = entry;
1113 break;
1114 }
1115 }
1116
1117 if (!renderbuffer) {
1118 gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
1119 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
1120 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER,
1121 This->resource.format_desc->glInternal, width, height);
1122
1123 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(renderbuffer_entry_t));
1124 entry->width = width;
1125 entry->height = height;
1126 entry->id = renderbuffer;
1127 list_add_head(&This->renderbuffers, &entry->entry);
1128
1129 This->current_renderbuffer = entry;
1130 }
1131
1132 checkGLcall("set_compatible_renderbuffer");
1133}
1134
1135GLenum surface_get_gl_buffer(IWineD3DSurface *iface)
1136{
1137 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1138 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *)This->container;
1139
1140 TRACE("iface %p.\n", iface);
1141
1142 if (!(This->Flags & SFLAG_SWAPCHAIN))
1143 {
1144 ERR("Surface %p is not on a swapchain.\n", iface);
1145 return GL_NONE;
1146 }
1147
1148 if (swapchain->backBuffer && swapchain->backBuffer[0] == iface)
1149 {
1150 if (swapchain->render_to_fbo)
1151 {
1152 TRACE("Returning GL_COLOR_ATTACHMENT0\n");
1153 return GL_COLOR_ATTACHMENT0;
1154 }
1155 TRACE("Returning GL_BACK\n");
1156 return GL_BACK;
1157 }
1158 else if (swapchain->frontBuffer == iface)
1159 {
1160 TRACE("Returning GL_FRONT\n");
1161 return GL_FRONT;
1162 }
1163
1164 FIXME("Higher back buffer, returning GL_BACK\n");
1165 return GL_BACK;
1166}
1167
1168#ifdef VBOX_WITH_WDDM
1169static HRESULT WINAPI IWineD3DSurfaceImpl_LoadLocation(IWineD3DSurface *iface, DWORD flag, const RECT *rect);
1170#endif
1171
1172/* Slightly inefficient way to handle multiple dirty rects but it works :) */
1173void surface_add_dirty_rect(IWineD3DSurface *iface, const RECT *dirty_rect)
1174{
1175 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1176 IWineD3DBaseTexture *baseTexture = NULL;
1177
1178 if (!(This->Flags & SFLAG_INSYSMEM) && (This->Flags & SFLAG_INTEXTURE))
1179 IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL /* no partial locking for textures yet */);
1180
1181 IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE);
1182
1183 if (dirty_rect)
1184 {
1185 This->dirtyRect.left = min(This->dirtyRect.left, dirty_rect->left);
1186 This->dirtyRect.top = min(This->dirtyRect.top, dirty_rect->top);
1187 This->dirtyRect.right = max(This->dirtyRect.right, dirty_rect->right);
1188 This->dirtyRect.bottom = max(This->dirtyRect.bottom, dirty_rect->bottom);
1189 }
1190 else
1191 {
1192 This->dirtyRect.left = 0;
1193 This->dirtyRect.top = 0;
1194 This->dirtyRect.right = This->currentDesc.Width;
1195 This->dirtyRect.bottom = This->currentDesc.Height;
1196 }
1197
1198 TRACE("(%p) : Dirty: yes, Rect:(%d, %d, %d, %d)\n", This, This->dirtyRect.left,
1199 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1200
1201 /* if the container is a basetexture then mark it dirty. */
1202 if (SUCCEEDED(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)))
1203 {
1204 TRACE("Passing to container\n");
1205 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
1206 IWineD3DBaseTexture_Release(baseTexture);
1207 }
1208}
1209
1210static BOOL surface_convert_color_to_argb(IWineD3DSurfaceImpl *This, DWORD color, DWORD *argb_color)
1211{
1212 IWineD3DDeviceImpl *device = This->resource.device;
1213
1214 switch(This->resource.format_desc->format)
1215 {
1216 case WINED3DFMT_P8_UINT:
1217 {
1218 DWORD alpha;
1219
1220 if (primary_render_target_is_p8(device))
1221 alpha = color << 24;
1222 else
1223 alpha = 0xFF000000;
1224
1225 if (This->palette) {
1226 *argb_color = (alpha |
1227 (This->palette->palents[color].peRed << 16) |
1228 (This->palette->palents[color].peGreen << 8) |
1229 (This->palette->palents[color].peBlue));
1230 } else {
1231 *argb_color = alpha;
1232 }
1233 }
1234 break;
1235
1236 case WINED3DFMT_B5G6R5_UNORM:
1237 {
1238 if (color == 0xFFFF) {
1239 *argb_color = 0xFFFFFFFF;
1240 } else {
1241 *argb_color = ((0xFF000000) |
1242 ((color & 0xF800) << 8) |
1243 ((color & 0x07E0) << 5) |
1244 ((color & 0x001F) << 3));
1245 }
1246 }
1247 break;
1248
1249 case WINED3DFMT_B8G8R8_UNORM:
1250 case WINED3DFMT_B8G8R8X8_UNORM:
1251 *argb_color = 0xFF000000 | color;
1252 break;
1253
1254 case WINED3DFMT_B8G8R8A8_UNORM:
1255 *argb_color = color;
1256 break;
1257
1258 default:
1259 ERR("Unhandled conversion from %s to ARGB!\n", debug_d3dformat(This->resource.format_desc->format));
1260 return FALSE;
1261 }
1262 return TRUE;
1263}
1264
1265static ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface)
1266{
1267 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1268 ULONG ref = InterlockedDecrement(&This->resource.ref);
1269 TRACE("(%p) : Releasing from %d\n", This, ref + 1);
1270
1271 if (!ref)
1272 {
1273#ifdef VBOX_WITH_WDDM
1274 IWineD3DDeviceImpl *device = This->resource.device;
1275 struct wined3d_context *context;
1276 UINT i;
1277#endif
1278 surface_cleanup(This);
1279 This->resource.parent_ops->wined3d_object_destroyed(This->resource.parent);
1280
1281#ifdef VBOX_WITH_WDDM
1282 for (i = 0; i < device->numContexts; ++i)
1283 {
1284 context = device->contexts[i];
1285 /* pretty hacky, @todo: check if the context is acquired and re-acquire it with the new swapchain */
1286 if (context->current_rt == (IWineD3DSurface*)This)
1287 {
1288 context->current_rt = NULL;
1289 }
1290 }
1291#endif
1292
1293 TRACE("(%p) Released.\n", This);
1294 HeapFree(GetProcessHeap(), 0, This);
1295 }
1296
1297 return ref;
1298}
1299
1300/* ****************************************************
1301 IWineD3DSurface IWineD3DResource parts follow
1302 **************************************************** */
1303
1304void surface_internal_preload(IWineD3DSurface *iface, enum WINED3DSRGB srgb)
1305{
1306 /* TODO: check for locks */
1307 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1308 IWineD3DDeviceImpl *device = This->resource.device;
1309 IWineD3DBaseTexture *baseTexture = NULL;
1310
1311 TRACE("(%p)Checking to see if the container is a base texture\n", This);
1312 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
1313 IWineD3DBaseTextureImpl *tex_impl = (IWineD3DBaseTextureImpl *) baseTexture;
1314 TRACE("Passing to container\n");
1315 tex_impl->baseTexture.internal_preload(baseTexture, srgb);
1316 IWineD3DBaseTexture_Release(baseTexture);
1317 } else {
1318 struct wined3d_context *context = NULL;
1319
1320 TRACE("(%p) : About to load surface\n", This);
1321
1322 if (!device->isInDraw) context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
1323
1324 if (This->resource.format_desc->format == WINED3DFMT_P8_UINT
1325 || This->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM)
1326 {
1327 if(palette9_changed(This)) {
1328 TRACE("Reloading surface because the d3d8/9 palette was changed\n");
1329 /* TODO: This is not necessarily needed with hw palettized texture support */
1330 IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL);
1331 /* Make sure the texture is reloaded because of the palette change, this kills performance though :( */
1332 IWineD3DSurface_ModifyLocation(iface, SFLAG_INTEXTURE, FALSE);
1333 }
1334 }
1335
1336 IWineD3DSurface_LoadTexture(iface, srgb == SRGB_SRGB ? TRUE : FALSE);
1337
1338 if (This->resource.pool == WINED3DPOOL_DEFAULT) {
1339 /* Tell opengl to try and keep this texture in video ram (well mostly) */
1340 GLclampf tmp;
1341 tmp = 0.9f;
1342#ifndef VBOX_WITH_WDDM
1343 ENTER_GL();
1344 glPrioritizeTextures(1, &This->texture_name, &tmp);
1345 LEAVE_GL();
1346#else
1347 /* chromium code on host fails to resolve texture name to texture obj for some reason
1348 * @todo: investigate */
1349#endif
1350 }
1351
1352 if (context) context_release(context);
1353 }
1354}
1355
1356static void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
1357 surface_internal_preload(iface, SRGB_ANY);
1358}
1359
1360/* Context activation is done by the caller. */
1361static void surface_remove_pbo(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info)
1362{
1363 This->resource.heapMemory = HeapAlloc(GetProcessHeap() ,0 , This->resource.size + RESOURCE_ALIGNMENT);
1364 This->resource.allocatedMemory =
1365 (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
1366
1367 ENTER_GL();
1368 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1369 checkGLcall("glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, This->pbo)");
1370 GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0, This->resource.size, This->resource.allocatedMemory));
1371 checkGLcall("glGetBufferSubDataARB");
1372 GL_EXTCALL(glDeleteBuffersARB(1, &This->pbo));
1373 checkGLcall("glDeleteBuffersARB");
1374 LEAVE_GL();
1375
1376 This->pbo = 0;
1377 This->Flags &= ~SFLAG_PBO;
1378}
1379
1380BOOL surface_init_sysmem(IWineD3DSurface *iface)
1381{
1382 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1383
1384 if(!This->resource.allocatedMemory)
1385 {
1386 This->resource.heapMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->resource.size + RESOURCE_ALIGNMENT);
1387 if(!This->resource.heapMemory)
1388 {
1389 ERR("Out of memory\n");
1390 return FALSE;
1391 }
1392 This->resource.allocatedMemory =
1393 (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
1394 }
1395 else
1396 {
1397 memset(This->resource.allocatedMemory, 0, This->resource.size);
1398 }
1399
1400 IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE);
1401 return TRUE;
1402}
1403
1404static void WINAPI IWineD3DSurfaceImpl_UnLoad(IWineD3DSurface *iface) {
1405 IWineD3DBaseTexture *texture = NULL;
1406 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1407 IWineD3DDeviceImpl *device = This->resource.device;
1408 const struct wined3d_gl_info *gl_info;
1409 renderbuffer_entry_t *entry, *entry2;
1410 struct wined3d_context *context;
1411
1412 TRACE("(%p)\n", iface);
1413
1414 if(This->resource.pool == WINED3DPOOL_DEFAULT) {
1415 /* Default pool resources are supposed to be destroyed before Reset is called.
1416 * Implicit resources stay however. So this means we have an implicit render target
1417 * or depth stencil. The content may be destroyed, but we still have to tear down
1418 * opengl resources, so we cannot leave early.
1419 *
1420 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
1421 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
1422 * or the depth stencil into an FBO the texture or render buffer will be removed
1423 * and all flags get lost
1424 */
1425 surface_init_sysmem(iface);
1426 } else {
1427 /* Load the surface into system memory */
1428 IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL);
1429 IWineD3DSurface_ModifyLocation(iface, SFLAG_INDRAWABLE, FALSE);
1430 }
1431 IWineD3DSurface_ModifyLocation(iface, SFLAG_INTEXTURE, FALSE);
1432 IWineD3DSurface_ModifyLocation(iface, SFLAG_INSRGBTEX, FALSE);
1433 This->Flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
1434
1435 context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
1436 gl_info = context->gl_info;
1437
1438 /* Destroy PBOs, but load them into real sysmem before */
1439 if (This->Flags & SFLAG_PBO)
1440 surface_remove_pbo(This, gl_info);
1441
1442 /* Destroy fbo render buffers. This is needed for implicit render targets, for
1443 * all application-created targets the application has to release the surface
1444 * before calling _Reset
1445 */
1446 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &This->renderbuffers, renderbuffer_entry_t, entry) {
1447 ENTER_GL();
1448 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
1449 LEAVE_GL();
1450 list_remove(&entry->entry);
1451 HeapFree(GetProcessHeap(), 0, entry);
1452 }
1453 list_init(&This->renderbuffers);
1454 This->current_renderbuffer = NULL;
1455
1456 /* If we're in a texture, the texture name belongs to the texture. Otherwise,
1457 * destroy it
1458 */
1459 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **) &texture);
1460 if(!texture) {
1461 ENTER_GL();
1462 texture_gl_delete(This, This->texture_name);
1463 texture_gl_delete(This, This->texture_name_srgb);
1464 This->texture_name = 0;
1465 This->texture_name_srgb = 0;
1466 LEAVE_GL();
1467 } else {
1468 IWineD3DBaseTexture_Release(texture);
1469 }
1470
1471 context_release(context);
1472}
1473
1474/* ******************************************************
1475 IWineD3DSurface IWineD3DSurface parts follow
1476 ****************************************************** */
1477
1478/* Read the framebuffer back into the surface */
1479static void read_from_framebuffer(IWineD3DSurfaceImpl *This, const RECT *rect, void *dest, UINT pitch)
1480{
1481 IWineD3DDeviceImpl *myDevice = This->resource.device;
1482 const struct wined3d_gl_info *gl_info;
1483 struct wined3d_context *context;
1484 BYTE *mem;
1485 GLint fmt;
1486 GLint type;
1487 BYTE *row, *top, *bottom;
1488 int i;
1489 BOOL bpp;
1490 RECT local_rect;
1491 BOOL srcIsUpsideDown;
1492 GLint rowLen = 0;
1493 GLint skipPix = 0;
1494 GLint skipRow = 0;
1495
1496 if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
1497 static BOOL warned = FALSE;
1498 if(!warned) {
1499 ERR("The application tries to lock the render target, but render target locking is disabled\n");
1500 warned = TRUE;
1501 }
1502 return;
1503 }
1504
1505 /* Activate the surface. Set it up for blitting now, although not necessarily needed for LockRect.
1506 * Certain graphics drivers seem to dislike some enabled states when reading from opengl, the blitting usage
1507 * should help here. Furthermore unlockrect will need the context set up for blitting. The context manager will find
1508 * context->last_was_blit set on the unlock.
1509 */
1510 context = context_acquire(myDevice, (IWineD3DSurface *) This, CTXUSAGE_BLIT);
1511 gl_info = context->gl_info;
1512
1513 ENTER_GL();
1514
1515 /* Select the correct read buffer, and give some debug output.
1516 * There is no need to keep track of the current read buffer or reset it, every part of the code
1517 * that reads sets the read buffer as desired.
1518 */
1519 if (surface_is_offscreen((IWineD3DSurface *) This))
1520 {
1521 /* Locking the primary render target which is not on a swapchain(=offscreen render target).
1522 * Read from the back buffer
1523 */
1524 TRACE("Locking offscreen render target\n");
1525 glReadBuffer(myDevice->offscreenBuffer);
1526 srcIsUpsideDown = TRUE;
1527 }
1528 else
1529 {
1530 /* Onscreen surfaces are always part of a swapchain */
1531 GLenum buffer = surface_get_gl_buffer((IWineD3DSurface *)This);
1532 TRACE("Locking %#x buffer\n", buffer);
1533 glReadBuffer(buffer);
1534 checkGLcall("glReadBuffer");
1535 srcIsUpsideDown = FALSE;
1536 }
1537
1538 /* TODO: Get rid of the extra rectangle comparison and construction of a full surface rectangle */
1539 if(!rect) {
1540 local_rect.left = 0;
1541 local_rect.top = 0;
1542 local_rect.right = This->currentDesc.Width;
1543 local_rect.bottom = This->currentDesc.Height;
1544 } else {
1545 local_rect = *rect;
1546 }
1547 /* TODO: Get rid of the extra GetPitch call, LockRect does that too. Cache the pitch */
1548
1549 switch(This->resource.format_desc->format)
1550 {
1551 case WINED3DFMT_P8_UINT:
1552 {
1553 if(primary_render_target_is_p8(myDevice)) {
1554 /* In case of P8 render targets the index is stored in the alpha component */
1555 fmt = GL_ALPHA;
1556 type = GL_UNSIGNED_BYTE;
1557 mem = dest;
1558 bpp = This->resource.format_desc->byte_count;
1559 } else {
1560 /* GL can't return palettized data, so read ARGB pixels into a
1561 * separate block of memory and convert them into palettized format
1562 * in software. Slow, but if the app means to use palettized render
1563 * targets and locks it...
1564 *
1565 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
1566 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
1567 * for the color channels when palettizing the colors.
1568 */
1569 fmt = GL_RGB;
1570 type = GL_UNSIGNED_BYTE;
1571 pitch *= 3;
1572 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * 3);
1573 if(!mem) {
1574 ERR("Out of memory\n");
1575 LEAVE_GL();
1576 return;
1577 }
1578 bpp = This->resource.format_desc->byte_count * 3;
1579 }
1580 }
1581 break;
1582
1583 default:
1584 mem = dest;
1585 fmt = This->resource.format_desc->glFormat;
1586 type = This->resource.format_desc->glType;
1587 bpp = This->resource.format_desc->byte_count;
1588 }
1589
1590 if(This->Flags & SFLAG_PBO) {
1591 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
1592 checkGLcall("glBindBufferARB");
1593 if(mem != NULL) {
1594 ERR("mem not null for pbo -- unexpected\n");
1595 mem = NULL;
1596 }
1597 }
1598
1599 /* Save old pixel store pack state */
1600 glGetIntegerv(GL_PACK_ROW_LENGTH, &rowLen);
1601 checkGLcall("glGetIntegerv");
1602 glGetIntegerv(GL_PACK_SKIP_PIXELS, &skipPix);
1603 checkGLcall("glGetIntegerv");
1604 glGetIntegerv(GL_PACK_SKIP_ROWS, &skipRow);
1605 checkGLcall("glGetIntegerv");
1606
1607 /* Setup pixel store pack state -- to glReadPixels into the correct place */
1608 glPixelStorei(GL_PACK_ROW_LENGTH, This->currentDesc.Width);
1609 checkGLcall("glPixelStorei");
1610 glPixelStorei(GL_PACK_SKIP_PIXELS, local_rect.left);
1611 checkGLcall("glPixelStorei");
1612 glPixelStorei(GL_PACK_SKIP_ROWS, local_rect.top);
1613 checkGLcall("glPixelStorei");
1614
1615 glReadPixels(local_rect.left, (!srcIsUpsideDown) ? (This->currentDesc.Height - local_rect.bottom) : local_rect.top ,
1616 local_rect.right - local_rect.left,
1617 local_rect.bottom - local_rect.top,
1618 fmt, type, mem);
1619 checkGLcall("glReadPixels");
1620
1621 /* Reset previous pixel store pack state */
1622 glPixelStorei(GL_PACK_ROW_LENGTH, rowLen);
1623 checkGLcall("glPixelStorei");
1624 glPixelStorei(GL_PACK_SKIP_PIXELS, skipPix);
1625 checkGLcall("glPixelStorei");
1626 glPixelStorei(GL_PACK_SKIP_ROWS, skipRow);
1627 checkGLcall("glPixelStorei");
1628
1629 if(This->Flags & SFLAG_PBO) {
1630 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
1631 checkGLcall("glBindBufferARB");
1632
1633 /* Check if we need to flip the image. If we need to flip use glMapBufferARB
1634 * to get a pointer to it and perform the flipping in software. This is a lot
1635 * faster than calling glReadPixels for each line. In case we want more speed
1636 * we should rerender it flipped in a FBO and read the data back from the FBO. */
1637 if(!srcIsUpsideDown) {
1638 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1639 checkGLcall("glBindBufferARB");
1640
1641 mem = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
1642 checkGLcall("glMapBufferARB");
1643 }
1644 }
1645
1646 /* TODO: Merge this with the palettization loop below for P8 targets */
1647 if(!srcIsUpsideDown) {
1648 UINT len, off;
1649 /* glReadPixels returns the image upside down, and there is no way to prevent this.
1650 Flip the lines in software */
1651 len = (local_rect.right - local_rect.left) * bpp;
1652 off = local_rect.left * bpp;
1653
1654 row = HeapAlloc(GetProcessHeap(), 0, len);
1655 if(!row) {
1656 ERR("Out of memory\n");
1657 if (This->resource.format_desc->format == WINED3DFMT_P8_UINT) HeapFree(GetProcessHeap(), 0, mem);
1658 LEAVE_GL();
1659 return;
1660 }
1661
1662 top = mem + pitch * local_rect.top;
1663 bottom = mem + pitch * (local_rect.bottom - 1);
1664 for(i = 0; i < (local_rect.bottom - local_rect.top) / 2; i++) {
1665 memcpy(row, top + off, len);
1666 memcpy(top + off, bottom + off, len);
1667 memcpy(bottom + off, row, len);
1668 top += pitch;
1669 bottom -= pitch;
1670 }
1671 HeapFree(GetProcessHeap(), 0, row);
1672
1673 /* Unmap the temp PBO buffer */
1674 if(This->Flags & SFLAG_PBO) {
1675 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
1676 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1677 }
1678 }
1679
1680 LEAVE_GL();
1681 context_release(context);
1682
1683 /* For P8 textures we need to perform an inverse palette lookup. This is done by searching for a palette
1684 * index which matches the RGB value. Note this isn't guaranteed to work when there are multiple entries for
1685 * the same color but we have no choice.
1686 * In case of P8 render targets, the index is stored in the alpha component so no conversion is needed.
1687 */
1688 if (This->resource.format_desc->format == WINED3DFMT_P8_UINT && !primary_render_target_is_p8(myDevice))
1689 {
1690 const PALETTEENTRY *pal = NULL;
1691 DWORD width = pitch / 3;
1692 int x, y, c;
1693
1694 if(This->palette) {
1695 pal = This->palette->palents;
1696 } else {
1697 ERR("Palette is missing, cannot perform inverse palette lookup\n");
1698 HeapFree(GetProcessHeap(), 0, mem);
1699 return ;
1700 }
1701
1702 for(y = local_rect.top; y < local_rect.bottom; y++) {
1703 for(x = local_rect.left; x < local_rect.right; x++) {
1704 /* start lines pixels */
1705 const BYTE *blue = mem + y * pitch + x * (sizeof(BYTE) * 3);
1706 const BYTE *green = blue + 1;
1707 const BYTE *red = green + 1;
1708
1709 for(c = 0; c < 256; c++) {
1710 if(*red == pal[c].peRed &&
1711 *green == pal[c].peGreen &&
1712 *blue == pal[c].peBlue)
1713 {
1714 *((BYTE *) dest + y * width + x) = c;
1715 break;
1716 }
1717 }
1718 }
1719 }
1720 HeapFree(GetProcessHeap(), 0, mem);
1721 }
1722}
1723
1724/* Read the framebuffer contents into a texture */
1725static void read_from_framebuffer_texture(IWineD3DSurfaceImpl *This, BOOL srgb)
1726{
1727 IWineD3DDeviceImpl *device = This->resource.device;
1728 const struct wined3d_gl_info *gl_info;
1729 struct wined3d_context *context;
1730 GLint prevRead;
1731 BOOL alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED;
1732
1733 /* Activate the surface to read from. In some situations it isn't the currently active target(e.g. backbuffer
1734 * locking during offscreen rendering). RESOURCELOAD is ok because glCopyTexSubImage2D isn't affected by any
1735 * states in the stateblock, and no driver was found yet that had bugs in that regard.
1736 */
1737 context = context_acquire(device, (IWineD3DSurface *) This, CTXUSAGE_RESOURCELOAD);
1738 gl_info = context->gl_info;
1739
1740 surface_bind_and_dirtify(This, srgb);
1741
1742 ENTER_GL();
1743 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1744 LEAVE_GL();
1745
1746 /* Select the correct read buffer, and give some debug output.
1747 * There is no need to keep track of the current read buffer or reset it, every part of the code
1748 * that reads sets the read buffer as desired.
1749 */
1750 if (!surface_is_offscreen((IWineD3DSurface *)This))
1751 {
1752 GLenum buffer = surface_get_gl_buffer((IWineD3DSurface *)This);
1753 TRACE("Locking %#x buffer\n", buffer);
1754
1755 ENTER_GL();
1756 glReadBuffer(buffer);
1757 checkGLcall("glReadBuffer");
1758 LEAVE_GL();
1759 }
1760 else
1761 {
1762 /* Locking the primary render target which is not on a swapchain(=offscreen render target).
1763 * Read from the back buffer
1764 */
1765 TRACE("Locking offscreen render target\n");
1766 ENTER_GL();
1767 glReadBuffer(device->offscreenBuffer);
1768 checkGLcall("glReadBuffer");
1769 LEAVE_GL();
1770 }
1771
1772 if (!(This->Flags & alloc_flag))
1773 {
1774 surface_allocate_surface(This, gl_info, This->resource.format_desc, srgb);
1775 This->Flags |= alloc_flag;
1776 }
1777
1778 ENTER_GL();
1779 /* If !SrcIsUpsideDown we should flip the surface.
1780 * This can be done using glCopyTexSubImage2D but this
1781 * is VERY slow, so don't do that. We should prevent
1782 * this code from getting called in such cases or perhaps
1783 * we can use FBOs */
1784
1785 glCopyTexSubImage2D(This->texture_target, This->texture_level,
1786 0, 0, 0, 0, This->currentDesc.Width, This->currentDesc.Height);
1787 checkGLcall("glCopyTexSubImage2D");
1788
1789 glReadBuffer(prevRead);
1790 checkGLcall("glReadBuffer");
1791
1792 LEAVE_GL();
1793
1794 context_release(context);
1795
1796 TRACE("Updated target %d\n", This->texture_target);
1797}
1798
1799/* Context activation is done by the caller. */
1800void surface_prepare_texture(IWineD3DSurfaceImpl *surface, const struct wined3d_gl_info *gl_info, BOOL srgb)
1801{
1802 DWORD alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED;
1803 CONVERT_TYPES convert;
1804 struct wined3d_format_desc desc;
1805
1806 if (surface->Flags & alloc_flag) return;
1807
1808 d3dfmt_get_conv(surface, TRUE, TRUE, &desc, &convert);
1809 if(convert != NO_CONVERSION) surface->Flags |= SFLAG_CONVERTED;
1810 else surface->Flags &= ~SFLAG_CONVERTED;
1811
1812 surface_bind_and_dirtify(surface, srgb);
1813 surface_allocate_surface(surface, gl_info, &desc, srgb);
1814 surface->Flags |= alloc_flag;
1815}
1816
1817#ifdef VBOX_WITH_WDDM
1818void surface_setup_location_onopen(IWineD3DSurfaceImpl *This)
1819{
1820 IWineD3DDeviceImpl *device = This->resource.device;
1821 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1822 DWORD alloc_flag = SFLAG_ALLOCATED;
1823 CONVERT_TYPES convert;
1824 struct wined3d_format_desc desc;
1825 IWineD3DBaseTexture *baseTexture = NULL;
1826 struct wined3d_context *context;
1827
1828 d3dfmt_get_conv(This, TRUE, TRUE, &desc, &convert);
1829 if(convert != NO_CONVERSION) This->Flags |= SFLAG_CONVERTED;
1830 else This->Flags &= ~SFLAG_CONVERTED;
1831
1832 if (IWineD3DSurface_GetContainer((IWineD3DSurface*)This, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
1833 IWineD3DTextureImpl* pTex = (IWineD3DTextureImpl*)baseTexture;
1834 if (!pTex->baseTexture.texture_rgb.name)
1835 {
1836 pTex->baseTexture.texture_rgb.name = (GLuint)VBOXSHRC_GET_SHAREHANDLE(pTex);
1837 /* @todo: this is not entirely correct: need to share this state among all instances of the given shared resource */
1838 texture_state_init((IWineD3DTexture*)baseTexture, &pTex->baseTexture.texture_rgb);
1839 context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
1840 ENTER_GL();
1841 GL_EXTCALL(glChromiumParameteriCR(GL_RCUSAGE_TEXTURE_SET_CR, pTex->baseTexture.texture_rgb.name));
1842 ENTER_GL();
1843 context_release(context);
1844 }
1845 IWineD3DBaseTexture_Release(baseTexture);
1846 }
1847 else
1848 {
1849 context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
1850 ENTER_GL();
1851 GL_EXTCALL(glChromiumParameteriCR(GL_RCUSAGE_TEXTURE_SET_CR, (GLuint)VBOXSHRC_GET_SHAREHANDLE(This)));
1852 ENTER_GL();
1853 context_release(context);
1854 }
1855 This->Flags |= alloc_flag;
1856 This->texture_name = (GLuint)VBOXSHRC_GET_SHAREHANDLE(This);
1857
1858 IWineD3DSurface_ModifyLocation((IWineD3DSurface*)This, SFLAG_INTEXTURE, TRUE);
1859}
1860#endif
1861
1862static void surface_prepare_system_memory(IWineD3DSurfaceImpl *This)
1863{
1864 IWineD3DDeviceImpl *device = This->resource.device;
1865 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1866
1867 /* Performance optimization: Count how often a surface is locked, if it is locked regularly do not throw away the system memory copy.
1868 * This avoids the need to download the surface from opengl all the time. The surface is still downloaded if the opengl texture is
1869 * changed
1870 */
1871 if(!(This->Flags & SFLAG_DYNLOCK)) {
1872 This->lockCount++;
1873 /* MAXLOCKCOUNT is defined in wined3d_private.h */
1874 if(This->lockCount > MAXLOCKCOUNT) {
1875 TRACE("Surface is locked regularly, not freeing the system memory copy any more\n");
1876 This->Flags |= SFLAG_DYNLOCK;
1877 }
1878 }
1879
1880 /* Create a PBO for dynamically locked surfaces but don't do it for converted or non-pow2 surfaces.
1881 * Also don't create a PBO for systemmem surfaces.
1882 */
1883 if (gl_info->supported[ARB_PIXEL_BUFFER_OBJECT] && (This->Flags & SFLAG_DYNLOCK)
1884 && !(This->Flags & (SFLAG_PBO | SFLAG_CONVERTED | SFLAG_NONPOW2))
1885 && (This->resource.pool != WINED3DPOOL_SYSTEMMEM))
1886 {
1887 GLenum error;
1888 struct wined3d_context *context;
1889
1890 context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
1891 ENTER_GL();
1892
1893 GL_EXTCALL(glGenBuffersARB(1, &This->pbo));
1894#ifndef VBOX_WITH_WDDM
1895 error = glGetError();
1896 if(This->pbo == 0 || error != GL_NO_ERROR) {
1897 ERR("Failed to bind the PBO with error %s (%#x)\n", debug_glerror(error), error);
1898 }
1899#else
1900 if(This->pbo == 0) {
1901 error = glGetError();
1902 ERR("Failed to bind the PBO with error %s (%#x)\n", debug_glerror(error), error);
1903 }
1904#endif
1905
1906 TRACE("Attaching pbo=%#x to (%p)\n", This->pbo, This);
1907
1908 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1909 checkGLcall("glBindBufferARB");
1910
1911 GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->resource.size + 4, This->resource.allocatedMemory, GL_STREAM_DRAW_ARB));
1912 checkGLcall("glBufferDataARB");
1913
1914 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1915 checkGLcall("glBindBufferARB");
1916
1917 /* We don't need the system memory anymore and we can't even use it for PBOs */
1918 if(!(This->Flags & SFLAG_CLIENT)) {
1919 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
1920 This->resource.heapMemory = NULL;
1921 }
1922 This->resource.allocatedMemory = NULL;
1923 This->Flags |= SFLAG_PBO;
1924 LEAVE_GL();
1925 context_release(context);
1926 }
1927 else if (!(This->resource.allocatedMemory || This->Flags & SFLAG_PBO))
1928 {
1929 /* Whatever surface we have, make sure that there is memory allocated for the downloaded copy,
1930 * or a pbo to map
1931 */
1932 if(!This->resource.heapMemory) {
1933 This->resource.heapMemory = HeapAlloc(GetProcessHeap() ,0 , This->resource.size + RESOURCE_ALIGNMENT);
1934 }
1935 This->resource.allocatedMemory =
1936 (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
1937 if(This->Flags & SFLAG_INSYSMEM) {
1938 ERR("Surface without memory or pbo has SFLAG_INSYSMEM set!\n");
1939 }
1940 }
1941}
1942
1943static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
1944 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1945 IWineD3DDeviceImpl *myDevice = This->resource.device;
1946 const RECT *pass_rect = pRect;
1947 HRESULT hr = S_OK;
1948
1949 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1950
1951 /* This is also done in the base class, but we have to verify this before loading any data from
1952 * gl into the sysmem copy. The PBO may be mapped, a different rectangle locked, the discard flag
1953 * may interfere, and all other bad things may happen
1954 */
1955 if (This->Flags & SFLAG_LOCKED) {
1956 WARN("Surface is already locked, returning D3DERR_INVALIDCALL\n");
1957 return WINED3DERR_INVALIDCALL;
1958 }
1959
1960#ifdef VBOX_WITH_WDDM
1961 surface_shrc_lock(This);
1962#endif
1963
1964 This->Flags |= SFLAG_LOCKED;
1965
1966 if (!(This->Flags & SFLAG_LOCKABLE))
1967 {
1968 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
1969 }
1970
1971 if (Flags & WINED3DLOCK_DISCARD) {
1972 /* Set SFLAG_INSYSMEM, so we'll never try to download the data from the texture. */
1973 TRACE("WINED3DLOCK_DISCARD flag passed, marking local copy as up to date\n");
1974 surface_prepare_system_memory(This); /* Makes sure memory is allocated */
1975 This->Flags |= SFLAG_INSYSMEM;
1976 goto lock_end;
1977 }
1978
1979 if (This->Flags & SFLAG_INSYSMEM) {
1980 TRACE("Local copy is up to date, not downloading data\n");
1981 surface_prepare_system_memory(This); /* Makes sure memory is allocated */
1982 goto lock_end;
1983 }
1984
1985 /* IWineD3DSurface_LoadLocation() does not check if the rectangle specifies
1986 * the full surface. Most callers don't need that, so do it here. */
1987 if (pRect && pRect->top == 0 && pRect->left == 0
1988 && pRect->right == This->currentDesc.Width
1989 && pRect->bottom == This->currentDesc.Height)
1990 {
1991 pass_rect = NULL;
1992 }
1993
1994 if (!(wined3d_settings.rendertargetlock_mode == RTL_DISABLE
1995 && ((This->Flags & SFLAG_SWAPCHAIN) || iface == myDevice->render_targets[0])))
1996 {
1997 IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, pass_rect);
1998 }
1999
2000lock_end:
2001 if (This->Flags & SFLAG_PBO)
2002 {
2003 const struct wined3d_gl_info *gl_info;
2004 struct wined3d_context *context;
2005
2006 context = context_acquire(myDevice, NULL, CTXUSAGE_RESOURCELOAD);
2007 gl_info = context->gl_info;
2008
2009 ENTER_GL();
2010 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
2011 checkGLcall("glBindBufferARB");
2012
2013 /* This shouldn't happen but could occur if some other function didn't handle the PBO properly */
2014 if(This->resource.allocatedMemory) {
2015 ERR("The surface already has PBO memory allocated!\n");
2016 }
2017
2018 This->resource.allocatedMemory = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
2019 checkGLcall("glMapBufferARB");
2020
2021 /* Make sure the pbo isn't set anymore in order not to break non-pbo calls */
2022 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
2023 checkGLcall("glBindBufferARB");
2024
2025 LEAVE_GL();
2026 context_release(context);
2027 }
2028
2029 if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
2030 /* Don't dirtify */
2031 } else {
2032 IWineD3DBaseTexture *pBaseTexture;
2033 /**
2034 * Dirtify on lock
2035 * as seen in msdn docs
2036 */
2037 surface_add_dirty_rect(iface, pRect);
2038
2039 /** Dirtify Container if needed */
2040 if (SUCCEEDED(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture))) {
2041 TRACE("Making container dirty\n");
2042 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
2043 IWineD3DBaseTexture_Release(pBaseTexture);
2044 } else {
2045 TRACE("Surface is standalone, no need to dirty the container\n");
2046 }
2047 }
2048
2049 hr = IWineD3DBaseSurfaceImpl_LockRect(iface, pLockedRect, pRect, Flags);
2050#ifdef VBOX_WITH_WDDM
2051 if (FAILED(hr))
2052 {
2053 WARN("IWineD3DBaseSurfaceImpl_LockRect failed, hr (%d)\n", hr);
2054 surface_shrc_unlock(This);
2055 }
2056 /* if lock succeeded, we keep the shrc locked until unlock */
2057#endif
2058 return hr;
2059}
2060
2061static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This, GLenum fmt, GLenum type, UINT bpp, const BYTE *mem) {
2062 GLint prev_store;
2063 GLint prev_rasterpos[4];
2064 GLint skipBytes = 0;
2065 UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This); /* target is argb, 4 byte */
2066 IWineD3DDeviceImpl *myDevice = This->resource.device;
2067 const struct wined3d_gl_info *gl_info;
2068 struct wined3d_context *context;
2069
2070 /* Activate the correct context for the render target */
2071 context = context_acquire(myDevice, (IWineD3DSurface *) This, CTXUSAGE_BLIT);
2072 gl_info = context->gl_info;
2073
2074 ENTER_GL();
2075
2076 if (!surface_is_offscreen((IWineD3DSurface *)This))
2077 {
2078 GLenum buffer = surface_get_gl_buffer((IWineD3DSurface *)This);
2079 TRACE("Unlocking %#x buffer.\n", buffer);
2080 context_set_draw_buffer(context, buffer);
2081 }
2082 else
2083 {
2084 /* Primary offscreen render target */
2085 TRACE("Offscreen render target.\n");
2086 context_set_draw_buffer(context, myDevice->offscreenBuffer);
2087 }
2088
2089 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
2090 checkGLcall("glGetIntegerv");
2091 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
2092 checkGLcall("glGetIntegerv");
2093 glPixelZoom(1.0f, -1.0f);
2094 checkGLcall("glPixelZoom");
2095
2096 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
2097 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
2098 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
2099
2100 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
2101 checkGLcall("glRasterPos3i");
2102
2103 /* Some drivers(radeon dri, others?) don't like exceptions during
2104 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
2105 * after ReleaseDC. Reading it will cause an exception, which x11drv will
2106 * catch to put the dib section in InSync mode, which leads to a crash
2107 * and a blocked x server on my radeon card.
2108 *
2109 * The following lines read the dib section so it is put in InSync mode
2110 * before glDrawPixels is called and the crash is prevented. There won't
2111 * be any interfering gdi accesses, because UnlockRect is called from
2112 * ReleaseDC, and the app won't use the dc any more afterwards.
2113 */
2114 if((This->Flags & SFLAG_DIBSECTION) && !(This->Flags & SFLAG_PBO)) {
2115 volatile BYTE read;
2116 read = This->resource.allocatedMemory[0];
2117 }
2118
2119 if(This->Flags & SFLAG_PBO) {
2120 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
2121 checkGLcall("glBindBufferARB");
2122 }
2123
2124 /* When the surface is locked we only have to refresh the locked part else we need to update the whole image */
2125 if(This->Flags & SFLAG_LOCKED) {
2126 glDrawPixels(This->lockedRect.right - This->lockedRect.left,
2127 (This->lockedRect.bottom - This->lockedRect.top)-1,
2128 fmt, type,
2129 mem + bpp * This->lockedRect.left + pitch * This->lockedRect.top);
2130 checkGLcall("glDrawPixels");
2131 } else {
2132 glDrawPixels(This->currentDesc.Width,
2133 This->currentDesc.Height,
2134 fmt, type, mem);
2135 checkGLcall("glDrawPixels");
2136 }
2137
2138 if(This->Flags & SFLAG_PBO) {
2139 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
2140 checkGLcall("glBindBufferARB");
2141 }
2142
2143 glPixelZoom(1.0f, 1.0f);
2144 checkGLcall("glPixelZoom");
2145
2146 glRasterPos3iv(&prev_rasterpos[0]);
2147 checkGLcall("glRasterPos3iv");
2148
2149 /* Reset to previous pack row length */
2150 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
2151 checkGLcall("glPixelStorei(GL_UNPACK_ROW_LENGTH)");
2152
2153 LEAVE_GL();
2154 context_release(context);
2155}
2156
2157static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
2158 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2159 IWineD3DDeviceImpl *myDevice = This->resource.device;
2160 BOOL fullsurface;
2161
2162 if (!(This->Flags & SFLAG_LOCKED)) {
2163 WARN("trying to Unlock an unlocked surf@%p\n", This);
2164 return WINEDDERR_NOTLOCKED;
2165 }
2166
2167 if (This->Flags & SFLAG_PBO)
2168 {
2169 const struct wined3d_gl_info *gl_info;
2170 struct wined3d_context *context;
2171
2172 TRACE("Freeing PBO memory\n");
2173
2174 context = context_acquire(myDevice, NULL, CTXUSAGE_RESOURCELOAD);
2175 gl_info = context->gl_info;
2176
2177 ENTER_GL();
2178 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
2179 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
2180 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
2181 checkGLcall("glUnmapBufferARB");
2182 LEAVE_GL();
2183 context_release(context);
2184
2185 This->resource.allocatedMemory = NULL;
2186 }
2187
2188 TRACE("(%p) : dirtyfied(%d)\n", This, This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1);
2189
2190 if (This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE)) {
2191 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
2192 goto unlock_end;
2193 }
2194
2195 if ((This->Flags & SFLAG_SWAPCHAIN) || (myDevice->render_targets && iface == myDevice->render_targets[0]))
2196 {
2197 if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
2198 static BOOL warned = FALSE;
2199 if(!warned) {
2200 ERR("The application tries to write to the render target, but render target locking is disabled\n");
2201 warned = TRUE;
2202 }
2203 goto unlock_end;
2204 }
2205
2206 if(This->dirtyRect.left == 0 &&
2207 This->dirtyRect.top == 0 &&
2208 This->dirtyRect.right == This->currentDesc.Width &&
2209 This->dirtyRect.bottom == This->currentDesc.Height) {
2210 fullsurface = TRUE;
2211 } else {
2212 /* TODO: Proper partial rectangle tracking */
2213 fullsurface = FALSE;
2214 This->Flags |= SFLAG_INSYSMEM;
2215 }
2216
2217 switch(wined3d_settings.rendertargetlock_mode) {
2218 case RTL_READTEX:
2219 IWineD3DSurface_LoadLocation(iface, SFLAG_INTEXTURE, NULL /* partial texture loading not supported yet */);
2220 /* drop through */
2221
2222 case RTL_READDRAW:
2223 IWineD3DSurface_LoadLocation(iface, SFLAG_INDRAWABLE, fullsurface ? NULL : &This->dirtyRect);
2224 break;
2225 }
2226
2227 if(!fullsurface) {
2228 /* Partial rectangle tracking is not commonly implemented, it is only done for render targets. Overwrite
2229 * the flags to bring them back into a sane state. INSYSMEM was set before to tell LoadLocation where
2230 * to read the rectangle from. Indrawable is set because all modifications from the partial sysmem copy
2231 * are written back to the drawable, thus the surface is merged again in the drawable. The sysmem copy is
2232 * not fully up to date because only a subrectangle was read in LockRect.
2233 */
2234 This->Flags &= ~SFLAG_INSYSMEM;
2235 This->Flags |= SFLAG_INDRAWABLE;
2236 }
2237
2238 This->dirtyRect.left = This->currentDesc.Width;
2239 This->dirtyRect.top = This->currentDesc.Height;
2240 This->dirtyRect.right = 0;
2241 This->dirtyRect.bottom = 0;
2242 } else if(iface == myDevice->stencilBufferTarget) {
2243 FIXME("Depth Stencil buffer locking is not implemented\n");
2244 } else {
2245 /* The rest should be a normal texture */
2246 IWineD3DBaseTextureImpl *impl;
2247 /* Check if the texture is bound, if yes dirtify the sampler to force a re-upload of the texture
2248 * Can't load the texture here because PreLoad may destroy and recreate the gl texture, so sampler
2249 * states need resetting
2250 */
2251 if(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&impl) == WINED3D_OK) {
2252 if(impl->baseTexture.bindCount) {
2253 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_SAMPLER(impl->baseTexture.sampler));
2254 }
2255 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *) impl);
2256 }
2257 }
2258
2259 unlock_end:
2260 This->Flags &= ~SFLAG_LOCKED;
2261 memset(&This->lockedRect, 0, sizeof(RECT));
2262
2263 /* Overlays have to be redrawn manually after changes with the GL implementation */
2264 if(This->overlay_dest) {
2265 IWineD3DSurface_DrawOverlay(iface);
2266 }
2267
2268#ifdef VBOX_WITH_WDDM
2269 surface_shrc_unlock(This);
2270#endif
2271
2272 return WINED3D_OK;
2273}
2274
2275static void surface_release_client_storage(IWineD3DSurface *iface)
2276{
2277 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2278 struct wined3d_context *context;
2279
2280#ifdef VBOX_WITH_WDDM
2281 if (VBOXSHRC_IS_SHARED(This))
2282 {
2283 ERR("surface_release_client_storage for shared resource! ignoring..");
2284 return;
2285 }
2286#endif
2287
2288 context = context_acquire(This->resource.device, NULL, CTXUSAGE_RESOURCELOAD);
2289
2290 ENTER_GL();
2291 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2292 if(This->texture_name)
2293 {
2294 surface_bind_and_dirtify(This, FALSE);
2295 glTexImage2D(This->texture_target, This->texture_level,
2296 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
2297 }
2298 if(This->texture_name_srgb)
2299 {
2300 surface_bind_and_dirtify(This, TRUE);
2301 glTexImage2D(This->texture_target, This->texture_level,
2302 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
2303 }
2304 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2305
2306 LEAVE_GL();
2307 context_release(context);
2308
2309 IWineD3DSurface_ModifyLocation(iface, SFLAG_INSRGBTEX, FALSE);
2310 IWineD3DSurface_ModifyLocation(iface, SFLAG_INTEXTURE, FALSE);
2311 surface_force_reload(iface);
2312}
2313
2314static HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC)
2315{
2316 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2317 WINED3DLOCKED_RECT lock;
2318 HRESULT hr;
2319 RGBQUAD col[256];
2320
2321 TRACE("(%p)->(%p)\n",This,pHDC);
2322
2323 if(This->Flags & SFLAG_USERPTR) {
2324 ERR("Not supported on surfaces with an application-provided surfaces\n");
2325 return WINEDDERR_NODC;
2326 }
2327
2328 /* Give more detailed info for ddraw */
2329 if (This->Flags & SFLAG_DCINUSE)
2330 return WINEDDERR_DCALREADYCREATED;
2331
2332 /* Can't GetDC if the surface is locked */
2333 if (This->Flags & SFLAG_LOCKED)
2334 return WINED3DERR_INVALIDCALL;
2335
2336 memset(&lock, 0, sizeof(lock)); /* To be sure */
2337
2338 /* Create a DIB section if there isn't a hdc yet */
2339 if(!This->hDC) {
2340 if(This->Flags & SFLAG_CLIENT) {
2341 IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL);
2342 surface_release_client_storage(iface);
2343 }
2344 hr = IWineD3DBaseSurfaceImpl_CreateDIBSection(iface);
2345 if(FAILED(hr)) return WINED3DERR_INVALIDCALL;
2346
2347 /* Use the dib section from now on if we are not using a PBO */
2348 if(!(This->Flags & SFLAG_PBO))
2349 This->resource.allocatedMemory = This->dib.bitmap_data;
2350 }
2351
2352 /* Lock the surface */
2353 hr = IWineD3DSurface_LockRect(iface,
2354 &lock,
2355 NULL,
2356 0);
2357
2358 if(This->Flags & SFLAG_PBO) {
2359 /* Sync the DIB with the PBO. This can't be done earlier because LockRect activates the allocatedMemory */
2360 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->dib.bitmap_size);
2361 }
2362
2363 if(FAILED(hr)) {
2364 ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr);
2365 /* keep the dib section */
2366 return hr;
2367 }
2368
2369 if (This->resource.format_desc->format == WINED3DFMT_P8_UINT
2370 || This->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM)
2371 {
2372 /* GetDC on palettized formats is unsupported in D3D9, and the method is missing in
2373 D3D8, so this should only be used for DX <=7 surfaces (with non-device palettes) */
2374 unsigned int n;
2375 const PALETTEENTRY *pal = NULL;
2376
2377 if(This->palette) {
2378 pal = This->palette->palents;
2379 } else {
2380 IWineD3DSurfaceImpl *dds_primary;
2381 IWineD3DSwapChainImpl *swapchain;
2382#ifdef VBOX_WITH_WDDM
2383 /* tmp work-around */
2384 swapchain = (IWineD3DSwapChainImpl *)This->resource.device->swapchains[This->resource.device->NumberOfSwapChains-1];
2385#else
2386 swapchain = (IWineD3DSwapChainImpl *)This->resource.device->swapchains[0];
2387#endif
2388 dds_primary = (IWineD3DSurfaceImpl *)swapchain->frontBuffer;
2389 if (dds_primary && dds_primary->palette)
2390 pal = dds_primary->palette->palents;
2391 }
2392
2393 if (pal) {
2394 for (n=0; n<256; n++) {
2395 col[n].rgbRed = pal[n].peRed;
2396 col[n].rgbGreen = pal[n].peGreen;
2397 col[n].rgbBlue = pal[n].peBlue;
2398 col[n].rgbReserved = 0;
2399 }
2400 SetDIBColorTable(This->hDC, 0, 256, col);
2401 }
2402 }
2403
2404 *pHDC = This->hDC;
2405 TRACE("returning %p\n",*pHDC);
2406 This->Flags |= SFLAG_DCINUSE;
2407
2408 return WINED3D_OK;
2409}
2410
2411static HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC)
2412{
2413 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2414
2415 TRACE("(%p)->(%p)\n",This,hDC);
2416
2417 if (!(This->Flags & SFLAG_DCINUSE))
2418 return WINEDDERR_NODC;
2419
2420 if (This->hDC !=hDC) {
2421 WARN("Application tries to release an invalid DC(%p), surface dc is %p\n", hDC, This->hDC);
2422 return WINEDDERR_NODC;
2423 }
2424
2425 if((This->Flags & SFLAG_PBO) && This->resource.allocatedMemory) {
2426 /* Copy the contents of the DIB over to the PBO */
2427 memcpy(This->resource.allocatedMemory, This->dib.bitmap_data, This->dib.bitmap_size);
2428 }
2429
2430 /* we locked first, so unlock now */
2431 IWineD3DSurface_UnlockRect(iface);
2432
2433 This->Flags &= ~SFLAG_DCINUSE;
2434
2435 return WINED3D_OK;
2436}
2437
2438/* ******************************************************
2439 IWineD3DSurface Internal (No mapping to directx api) parts follow
2440 ****************************************************** */
2441
2442HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, BOOL use_texturing, struct wined3d_format_desc *desc, CONVERT_TYPES *convert)
2443{
2444 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & WINEDDSD_CKSRCBLT);
2445 IWineD3DDeviceImpl *device = This->resource.device;
2446 BOOL blit_supported = FALSE;
2447 RECT rect = {0, 0, This->pow2Width, This->pow2Height};
2448
2449 /* Copy the default values from the surface. Below we might perform fixups */
2450 /* TODO: get rid of color keying desc fixups by using e.g. a table. */
2451 *desc = *This->resource.format_desc;
2452 *convert = NO_CONVERSION;
2453
2454 /* Ok, now look if we have to do any conversion */
2455 switch(This->resource.format_desc->format)
2456 {
2457 case WINED3DFMT_P8_UINT:
2458 /* ****************
2459 Paletted Texture
2460 **************** */
2461
2462 blit_supported = device->blitter->blit_supported(&device->adapter->gl_info, BLIT_OP_BLIT,
2463 &rect, This->resource.usage, This->resource.pool,
2464 This->resource.format_desc, &rect, This->resource.usage,
2465 This->resource.pool, This->resource.format_desc);
2466
2467 /* Use conversion when the blit_shader backend supports it. It only supports this in case of
2468 * texturing. Further also use conversion in case of color keying.
2469 * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
2470 * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
2471 * conflicts with this.
2472 */
2473 if (!((blit_supported && device->render_targets && This == (IWineD3DSurfaceImpl*)device->render_targets[0]))
2474 || colorkey_active || !use_texturing)
2475 {
2476 desc->glFormat = GL_RGBA;
2477 desc->glInternal = GL_RGBA;
2478 desc->glType = GL_UNSIGNED_BYTE;
2479 desc->conv_byte_count = 4;
2480 if(colorkey_active) {
2481 *convert = CONVERT_PALETTED_CK;
2482 } else {
2483 *convert = CONVERT_PALETTED;
2484 }
2485 }
2486 break;
2487
2488 case WINED3DFMT_B2G3R3_UNORM:
2489 /* **********************
2490 GL_UNSIGNED_BYTE_3_3_2
2491 ********************** */
2492 if (colorkey_active) {
2493 /* This texture format will never be used.. So do not care about color keying
2494 up until the point in time it will be needed :-) */
2495 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
2496 }
2497 break;
2498
2499 case WINED3DFMT_B5G6R5_UNORM:
2500 if (colorkey_active) {
2501 *convert = CONVERT_CK_565;
2502 desc->glFormat = GL_RGBA;
2503 desc->glInternal = GL_RGB5_A1;
2504 desc->glType = GL_UNSIGNED_SHORT_5_5_5_1;
2505 desc->conv_byte_count = 2;
2506 }
2507 break;
2508
2509 case WINED3DFMT_B5G5R5X1_UNORM:
2510 if (colorkey_active) {
2511 *convert = CONVERT_CK_5551;
2512 desc->glFormat = GL_BGRA;
2513 desc->glInternal = GL_RGB5_A1;
2514 desc->glType = GL_UNSIGNED_SHORT_1_5_5_5_REV;
2515 desc->conv_byte_count = 2;
2516 }
2517 break;
2518
2519 case WINED3DFMT_B8G8R8_UNORM:
2520 if (colorkey_active) {
2521 *convert = CONVERT_CK_RGB24;
2522 desc->glFormat = GL_RGBA;
2523 desc->glInternal = GL_RGBA8;
2524 desc->glType = GL_UNSIGNED_INT_8_8_8_8;
2525 desc->conv_byte_count = 4;
2526 }
2527 break;
2528
2529 case WINED3DFMT_B8G8R8X8_UNORM:
2530 if (colorkey_active) {
2531 *convert = CONVERT_RGB32_888;
2532 desc->glFormat = GL_RGBA;
2533 desc->glInternal = GL_RGBA8;
2534 desc->glType = GL_UNSIGNED_INT_8_8_8_8;
2535 desc->conv_byte_count = 4;
2536 }
2537 break;
2538
2539 default:
2540 break;
2541 }
2542
2543 return WINED3D_OK;
2544}
2545
2546void d3dfmt_p8_init_palette(IWineD3DSurfaceImpl *This, BYTE table[256][4], BOOL colorkey)
2547{
2548 IWineD3DDeviceImpl *device = This->resource.device;
2549 IWineD3DPaletteImpl *pal = This->palette;
2550 BOOL index_in_alpha = FALSE;
2551 unsigned int i;
2552
2553 /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
2554 * Reading back the RGB output each lockrect (each frame as they lock the whole screen)
2555 * is slow. Further RGB->P8 conversion is not possible because palettes can have
2556 * duplicate entries. Store the color key in the unused alpha component to speed the
2557 * download up and to make conversion unneeded. */
2558 index_in_alpha = primary_render_target_is_p8(device);
2559
2560 if (!pal)
2561 {
2562 UINT dxVersion = ((IWineD3DImpl *)device->wined3d)->dxVersion;
2563
2564 /* In DirectDraw the palette is a property of the surface, there are no such things as device palettes. */
2565 if (dxVersion <= 7)
2566 {
2567 ERR("This code should never get entered for DirectDraw!, expect problems\n");
2568 if (index_in_alpha)
2569 {
2570 /* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
2571 * there's no palette at this time. */
2572 for (i = 0; i < 256; i++) table[i][3] = i;
2573 }
2574 }
2575 else
2576 {
2577 /* Direct3D >= 8 palette usage style: P8 textures use device palettes, palette entry format is A8R8G8B8,
2578 * alpha is stored in peFlags and may be used by the app if D3DPTEXTURECAPS_ALPHAPALETTE device
2579 * capability flag is present (wine does advertise this capability) */
2580 for (i = 0; i < 256; ++i)
2581 {
2582 table[i][0] = device->palettes[device->currentPalette][i].peRed;
2583 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
2584 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
2585 table[i][3] = device->palettes[device->currentPalette][i].peFlags;
2586 }
2587 }
2588 }
2589 else
2590 {
2591 TRACE("Using surface palette %p\n", pal);
2592 /* Get the surface's palette */
2593 for (i = 0; i < 256; ++i)
2594 {
2595 table[i][0] = pal->palents[i].peRed;
2596 table[i][1] = pal->palents[i].peGreen;
2597 table[i][2] = pal->palents[i].peBlue;
2598
2599 /* When index_in_alpha is set the palette index is stored in the
2600 * alpha component. In case of a readback we can then read
2601 * GL_ALPHA. Color keying is handled in BltOverride using a
2602 * GL_ALPHA_TEST using GL_NOT_EQUAL. In case of index_in_alpha the
2603 * color key itself is passed to glAlphaFunc in other cases the
2604 * alpha component of pixels that should be masked away is set to 0. */
2605 if (index_in_alpha)
2606 {
2607 table[i][3] = i;
2608 }
2609 else if (colorkey && (i >= This->SrcBltCKey.dwColorSpaceLowValue)
2610 && (i <= This->SrcBltCKey.dwColorSpaceHighValue))
2611 {
2612 table[i][3] = 0x00;
2613 }
2614 else if(pal->Flags & WINEDDPCAPS_ALPHA)
2615 {
2616 table[i][3] = pal->palents[i].peFlags;
2617 }
2618 else
2619 {
2620 table[i][3] = 0xFF;
2621 }
2622 }
2623 }
2624}
2625
2626static HRESULT d3dfmt_convert_surface(const BYTE *src, BYTE *dst, UINT pitch, UINT width,
2627 UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *This)
2628{
2629 const BYTE *source;
2630 BYTE *dest;
2631 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert,This);
2632
2633 switch (convert) {
2634 case NO_CONVERSION:
2635 {
2636 memcpy(dst, src, pitch * height);
2637 break;
2638 }
2639 case CONVERT_PALETTED:
2640 case CONVERT_PALETTED_CK:
2641 {
2642 IWineD3DPaletteImpl* pal = This->palette;
2643 BYTE table[256][4];
2644 unsigned int x, y;
2645
2646 if( pal == NULL) {
2647 /* TODO: If we are a sublevel, try to get the palette from level 0 */
2648 }
2649
2650 d3dfmt_p8_init_palette(This, table, (convert == CONVERT_PALETTED_CK));
2651
2652 for (y = 0; y < height; y++)
2653 {
2654 source = src + pitch * y;
2655 dest = dst + outpitch * y;
2656 /* This is an 1 bpp format, using the width here is fine */
2657 for (x = 0; x < width; x++) {
2658 BYTE color = *source++;
2659 *dest++ = table[color][0];
2660 *dest++ = table[color][1];
2661 *dest++ = table[color][2];
2662 *dest++ = table[color][3];
2663 }
2664 }
2665 }
2666 break;
2667
2668 case CONVERT_CK_565:
2669 {
2670 /* Converting the 565 format in 5551 packed to emulate color-keying.
2671
2672 Note : in all these conversion, it would be best to average the averaging
2673 pixels to get the color of the pixel that will be color-keyed to
2674 prevent 'color bleeding'. This will be done later on if ever it is
2675 too visible.
2676
2677 Note2: Nvidia documents say that their driver does not support alpha + color keying
2678 on the same surface and disables color keying in such a case
2679 */
2680 unsigned int x, y;
2681 const WORD *Source;
2682 WORD *Dest;
2683
2684 TRACE("Color keyed 565\n");
2685
2686 for (y = 0; y < height; y++) {
2687 Source = (const WORD *)(src + y * pitch);
2688 Dest = (WORD *) (dst + y * outpitch);
2689 for (x = 0; x < width; x++ ) {
2690 WORD color = *Source++;
2691 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
2692 if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
2693 (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
2694 *Dest |= 0x0001;
2695 }
2696 Dest++;
2697 }
2698 }
2699 }
2700 break;
2701
2702 case CONVERT_CK_5551:
2703 {
2704 /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
2705 unsigned int x, y;
2706 const WORD *Source;
2707 WORD *Dest;
2708 TRACE("Color keyed 5551\n");
2709 for (y = 0; y < height; y++) {
2710 Source = (const WORD *)(src + y * pitch);
2711 Dest = (WORD *) (dst + y * outpitch);
2712 for (x = 0; x < width; x++ ) {
2713 WORD color = *Source++;
2714 *Dest = color;
2715 if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
2716 (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
2717 *Dest |= (1 << 15);
2718 }
2719 else {
2720 *Dest &= ~(1 << 15);
2721 }
2722 Dest++;
2723 }
2724 }
2725 }
2726 break;
2727
2728 case CONVERT_CK_RGB24:
2729 {
2730 /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
2731 unsigned int x, y;
2732 for (y = 0; y < height; y++)
2733 {
2734 source = src + pitch * y;
2735 dest = dst + outpitch * y;
2736 for (x = 0; x < width; x++) {
2737 DWORD color = ((DWORD)source[0] << 16) + ((DWORD)source[1] << 8) + (DWORD)source[2] ;
2738 DWORD dstcolor = color << 8;
2739 if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
2740 (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
2741 dstcolor |= 0xff;
2742 }
2743 *(DWORD*)dest = dstcolor;
2744 source += 3;
2745 dest += 4;
2746 }
2747 }
2748 }
2749 break;
2750
2751 case CONVERT_RGB32_888:
2752 {
2753 /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
2754 unsigned int x, y;
2755 for (y = 0; y < height; y++)
2756 {
2757 source = src + pitch * y;
2758 dest = dst + outpitch * y;
2759 for (x = 0; x < width; x++) {
2760 DWORD color = 0xffffff & *(const DWORD*)source;
2761 DWORD dstcolor = color << 8;
2762 if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
2763 (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
2764 dstcolor |= 0xff;
2765 }
2766 *(DWORD*)dest = dstcolor;
2767 source += 4;
2768 dest += 4;
2769 }
2770 }
2771 }
2772 break;
2773
2774 default:
2775 ERR("Unsupported conversion type %#x.\n", convert);
2776 }
2777 return WINED3D_OK;
2778}
2779
2780BOOL palette9_changed(IWineD3DSurfaceImpl *This)
2781{
2782 IWineD3DDeviceImpl *device = This->resource.device;
2783
2784 if (This->palette || (This->resource.format_desc->format != WINED3DFMT_P8_UINT
2785 && This->resource.format_desc->format != WINED3DFMT_P8_UINT_A8_UNORM))
2786 {
2787 /* If a ddraw-style palette is attached assume no d3d9 palette change.
2788 * Also the palette isn't interesting if the surface format isn't P8 or A8P8
2789 */
2790 return FALSE;
2791 }
2792
2793 if (This->palette9)
2794 {
2795 if (!memcmp(This->palette9, device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256))
2796 {
2797 return FALSE;
2798 }
2799 } else {
2800 This->palette9 = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2801 }
2802 memcpy(This->palette9, device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256);
2803 return TRUE;
2804}
2805
2806static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface, BOOL srgb_mode) {
2807 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2808 DWORD flag = srgb_mode ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
2809
2810 if (!(This->Flags & flag)) {
2811 TRACE("Reloading because surface is dirty\n");
2812 } else if(/* Reload: gl texture has ck, now no ckey is set OR */
2813 ((This->Flags & SFLAG_GLCKEY) && (!(This->CKeyFlags & WINEDDSD_CKSRCBLT))) ||
2814 /* Reload: vice versa OR */
2815 ((!(This->Flags & SFLAG_GLCKEY)) && (This->CKeyFlags & WINEDDSD_CKSRCBLT)) ||
2816 /* Also reload: Color key is active AND the color key has changed */
2817 ((This->CKeyFlags & WINEDDSD_CKSRCBLT) && (
2818 (This->glCKey.dwColorSpaceLowValue != This->SrcBltCKey.dwColorSpaceLowValue) ||
2819 (This->glCKey.dwColorSpaceHighValue != This->SrcBltCKey.dwColorSpaceHighValue)))) {
2820 TRACE("Reloading because of color keying\n");
2821 /* To perform the color key conversion we need a sysmem copy of
2822 * the surface. Make sure we have it
2823 */
2824
2825 IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL);
2826 /* Make sure the texture is reloaded because of the color key change, this kills performance though :( */
2827 /* TODO: This is not necessarily needed with hw palettized texture support */
2828 IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE);
2829 } else {
2830 TRACE("surface is already in texture\n");
2831 return WINED3D_OK;
2832 }
2833
2834 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
2835 * These resources are not bound by device size or format restrictions. Because of this,
2836 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
2837 * However, these resources can always be created, locked, and copied.
2838 */
2839 if (This->resource.pool == WINED3DPOOL_SCRATCH )
2840 {
2841 FIXME("(%p) Operation not supported for scratch textures\n",This);
2842 return WINED3DERR_INVALIDCALL;
2843 }
2844
2845 IWineD3DSurface_LoadLocation(iface, flag, NULL /* no partial locking for textures yet */);
2846
2847#if 0
2848 {
2849 static unsigned int gen = 0;
2850 char buffer[4096];
2851 ++gen;
2852 if ((gen % 10) == 0) {
2853 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm",
2854 This, This->texture_target, This->texture_level, gen);
2855 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
2856 }
2857 /*
2858 * debugging crash code
2859 if (gen == 250) {
2860 void** test = NULL;
2861 *test = 0;
2862 }
2863 */
2864 }
2865#endif
2866
2867 if (!(This->Flags & SFLAG_DONOTFREE)) {
2868 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
2869 This->resource.allocatedMemory = NULL;
2870 This->resource.heapMemory = NULL;
2871 IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, FALSE);
2872 }
2873
2874 return WINED3D_OK;
2875}
2876
2877/* Context activation is done by the caller. */
2878static void WINAPI IWineD3DSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
2879 /* TODO: check for locks */
2880 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2881 IWineD3DBaseTexture *baseTexture = NULL;
2882
2883 TRACE("(%p)Checking to see if the container is a base texture\n", This);
2884 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
2885 TRACE("Passing to container\n");
2886 IWineD3DBaseTexture_BindTexture(baseTexture, srgb);
2887 IWineD3DBaseTexture_Release(baseTexture);
2888 }
2889 else
2890 {
2891 GLuint *name;
2892
2893 TRACE("(%p) : Binding surface\n", This);
2894
2895 name = srgb ? &This->texture_name_srgb : &This->texture_name;
2896
2897 ENTER_GL();
2898
2899 if (!This->texture_level)
2900 {
2901 if (!*name) {
2902#ifdef VBOX_WITH_WDDM
2903 if (VBOXSHRC_IS_SHARED_OPENED(This))
2904 {
2905 struct wined3d_gl_info *gl_info = &This->resource.device->adapter->gl_info;
2906 ERR("should not be here!");
2907 *name = (GLuint)VBOXSHRC_GET_SHAREHANDLE(This);
2908 GL_EXTCALL(glChromiumParameteriCR(GL_RCUSAGE_TEXTURE_SET_CR, name));
2909 }
2910 else
2911#endif
2912 {
2913 glGenTextures(1, name);
2914 checkGLcall("glGenTextures");
2915 TRACE("Surface %p given name %d\n", This, *name);
2916
2917 glBindTexture(This->texture_target, *name);
2918 checkGLcall("glBindTexture");
2919 glTexParameteri(This->texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2920 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)");
2921 glTexParameteri(This->texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2922 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)");
2923 glTexParameteri(This->texture_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
2924 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE)");
2925 glTexParameteri(This->texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2926 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_MIN_FILTER, GL_NEAREST)");
2927 glTexParameteri(This->texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2928 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_MAG_FILTER, GL_NEAREST)");
2929#ifdef VBOX_WITH_WDDM
2930 if (VBOXSHRC_IS_SHARED(This))
2931 {
2932 VBOXSHRC_SET_SHAREHANDLE(This, *name);
2933 }
2934#endif
2935 }
2936 }
2937 /* This is where we should be reducing the amount of GLMemoryUsed */
2938 } else if (*name) {
2939 /* Mipmap surfaces should have a base texture container */
2940 ERR("Mipmap surface has a glTexture bound to it!\n");
2941 }
2942
2943 glBindTexture(This->texture_target, *name);
2944 checkGLcall("glBindTexture");
2945
2946 LEAVE_GL();
2947 }
2948}
2949
2950#include <errno.h>
2951#include <stdio.h>
2952static HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename)
2953{
2954 FILE* f = NULL;
2955 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2956 char *allocatedMemory;
2957 const char *textureRow;
2958 IWineD3DSwapChain *swapChain = NULL;
2959 int width, height, i, y;
2960 GLuint tmpTexture = 0;
2961 DWORD color;
2962 /*FIXME:
2963 Textures may not be stored in ->allocatedgMemory and a GlTexture
2964 so we should lock the surface before saving a snapshot, or at least check that
2965 */
2966 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
2967 by calling GetTexImage and in compressed form by calling
2968 GetCompressedTexImageARB. Queried compressed images can be saved and
2969 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
2970 texture images do not need to be processed by the GL and should
2971 significantly improve texture loading performance relative to uncompressed
2972 images. */
2973
2974/* Setup the width and height to be the internal texture width and height. */
2975 width = This->pow2Width;
2976 height = This->pow2Height;
2977/* check to see if we're a 'virtual' texture, e.g. we're not a pbuffer of texture, we're a back buffer*/
2978 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
2979
2980 if (This->Flags & SFLAG_INDRAWABLE && !(This->Flags & SFLAG_INTEXTURE)) {
2981 /* if were not a real texture then read the back buffer into a real texture */
2982 /* we don't want to interfere with the back buffer so read the data into a temporary
2983 * texture and then save the data out of the temporary texture
2984 */
2985 GLint prevRead;
2986 ENTER_GL();
2987 TRACE("(%p) Reading render target into texture\n", This);
2988
2989 glGenTextures(1, &tmpTexture);
2990 glBindTexture(GL_TEXTURE_2D, tmpTexture);
2991
2992 glTexImage2D(GL_TEXTURE_2D,
2993 0,
2994 GL_RGBA,
2995 width,
2996 height,
2997 0/*border*/,
2998 GL_RGBA,
2999 GL_UNSIGNED_INT_8_8_8_8_REV,
3000 NULL);
3001
3002 glGetIntegerv(GL_READ_BUFFER, &prevRead);
3003 checkGLcall("glGetIntegerv");
3004 glReadBuffer(swapChain ? GL_BACK : This->resource.device->offscreenBuffer);
3005 checkGLcall("glReadBuffer");
3006 glCopyTexImage2D(GL_TEXTURE_2D,
3007 0,
3008 GL_RGBA,
3009 0,
3010 0,
3011 width,
3012 height,
3013 0);
3014
3015 checkGLcall("glCopyTexImage2D");
3016 glReadBuffer(prevRead);
3017 LEAVE_GL();
3018
3019 } else { /* bind the real texture, and make sure it up to date */
3020 surface_internal_preload(iface, SRGB_RGB);
3021 surface_bind_and_dirtify(This, FALSE);
3022 }
3023 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
3024 ENTER_GL();
3025 FIXME("Saving texture level %d width %d height %d\n", This->texture_level, width, height);
3026 glGetTexImage(GL_TEXTURE_2D, This->texture_level, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, allocatedMemory);
3027 checkGLcall("glGetTexImage");
3028 if (tmpTexture) {
3029 glBindTexture(GL_TEXTURE_2D, 0);
3030 glDeleteTextures(1, &tmpTexture);
3031 }
3032 LEAVE_GL();
3033
3034 f = fopen(filename, "w+");
3035 if (NULL == f) {
3036 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
3037 return WINED3DERR_INVALIDCALL;
3038 }
3039/* Save the data out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha channel */
3040 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format_desc->format));
3041/* TGA header */
3042 fputc(0,f);
3043 fputc(0,f);
3044 fputc(2,f);
3045 fputc(0,f);
3046 fputc(0,f);
3047 fputc(0,f);
3048 fputc(0,f);
3049 fputc(0,f);
3050 fputc(0,f);
3051 fputc(0,f);
3052 fputc(0,f);
3053 fputc(0,f);
3054/* short width*/
3055 fwrite(&width,2,1,f);
3056/* short height */
3057 fwrite(&height,2,1,f);
3058/* format rgba */
3059 fputc(0x20,f);
3060 fputc(0x28,f);
3061/* raw data */
3062 /* if the data is upside down if we've fetched it from a back buffer, so it needs flipping again to make it the correct way up */
3063 if(swapChain)
3064 textureRow = allocatedMemory + (width * (height - 1) *4);
3065 else
3066 textureRow = allocatedMemory;
3067 for (y = 0 ; y < height; y++) {
3068 for (i = 0; i < width; i++) {
3069 color = *((const DWORD*)textureRow);
3070 fputc((color >> 16) & 0xFF, f); /* B */
3071 fputc((color >> 8) & 0xFF, f); /* G */
3072 fputc((color >> 0) & 0xFF, f); /* R */
3073 fputc((color >> 24) & 0xFF, f); /* A */
3074 textureRow += 4;
3075 }
3076 /* take two rows of the pointer to the texture memory */
3077 if(swapChain)
3078 (textureRow-= width << 3);
3079
3080 }
3081 TRACE("Closing file\n");
3082 fclose(f);
3083
3084 if(swapChain) {
3085 IWineD3DSwapChain_Release(swapChain);
3086 }
3087 HeapFree(GetProcessHeap(), 0, allocatedMemory);
3088 return WINED3D_OK;
3089}
3090
3091static HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
3092 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
3093 HRESULT hr;
3094
3095 TRACE("(%p) : Calling base function first\n", This);
3096 hr = IWineD3DBaseSurfaceImpl_SetFormat(iface, format);
3097 if(SUCCEEDED(hr)) {
3098 This->Flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
3099 TRACE("(%p) : glFormat %d, glFormatInternal %d, glType %d\n", This, This->resource.format_desc->glFormat,
3100 This->resource.format_desc->glInternal, This->resource.format_desc->glType);
3101 }
3102 return hr;
3103}
3104
3105static HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
3106 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3107
3108 if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
3109 WARN("Surface is locked or the HDC is in use\n");
3110 return WINED3DERR_INVALIDCALL;
3111 }
3112
3113 if(Mem && Mem != This->resource.allocatedMemory) {
3114 void *release = NULL;
3115
3116 /* Do I have to copy the old surface content? */
3117 if(This->Flags & SFLAG_DIBSECTION) {
3118 /* Release the DC. No need to hold the critical section for the update
3119 * Thread because this thread runs only on front buffers, but this method
3120 * fails for render targets in the check above.
3121 */
3122 SelectObject(This->hDC, This->dib.holdbitmap);
3123 DeleteDC(This->hDC);
3124 /* Release the DIB section */
3125 DeleteObject(This->dib.DIBsection);
3126 This->dib.bitmap_data = NULL;
3127 This->resource.allocatedMemory = NULL;
3128 This->hDC = NULL;
3129 This->Flags &= ~SFLAG_DIBSECTION;
3130 } else if(!(This->Flags & SFLAG_USERPTR)) {
3131 release = This->resource.heapMemory;
3132 This->resource.heapMemory = NULL;
3133 }
3134 This->resource.allocatedMemory = Mem;
3135 This->Flags |= SFLAG_USERPTR | SFLAG_INSYSMEM;
3136
3137 /* Now the surface memory is most up do date. Invalidate drawable and texture */
3138 IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE);
3139
3140 /* For client textures opengl has to be notified */
3141 if(This->Flags & SFLAG_CLIENT) {
3142 surface_release_client_storage(iface);
3143 }
3144
3145 /* Now free the old memory if any */
3146 HeapFree(GetProcessHeap(), 0, release);
3147 } else if(This->Flags & SFLAG_USERPTR) {
3148 /* LockRect and GetDC will re-create the dib section and allocated memory */
3149 This->resource.allocatedMemory = NULL;
3150 /* HeapMemory should be NULL already */
3151 if(This->resource.heapMemory != NULL) ERR("User pointer surface has heap memory allocated\n");
3152 This->Flags &= ~SFLAG_USERPTR;
3153
3154 if(This->Flags & SFLAG_CLIENT) {
3155 surface_release_client_storage(iface);
3156 }
3157 }
3158 return WINED3D_OK;
3159}
3160
3161void flip_surface(IWineD3DSurfaceImpl *front, IWineD3DSurfaceImpl *back) {
3162
3163 /* Flip the surface contents */
3164 /* Flip the DC */
3165 {
3166 HDC tmp;
3167 tmp = front->hDC;
3168 front->hDC = back->hDC;
3169 back->hDC = tmp;
3170 }
3171
3172 /* Flip the DIBsection */
3173 {
3174 HBITMAP tmp;
3175 BOOL hasDib = front->Flags & SFLAG_DIBSECTION;
3176 tmp = front->dib.DIBsection;
3177 front->dib.DIBsection = back->dib.DIBsection;
3178 back->dib.DIBsection = tmp;
3179
3180 if(back->Flags & SFLAG_DIBSECTION) front->Flags |= SFLAG_DIBSECTION;
3181 else front->Flags &= ~SFLAG_DIBSECTION;
3182 if(hasDib) back->Flags |= SFLAG_DIBSECTION;
3183 else back->Flags &= ~SFLAG_DIBSECTION;
3184 }
3185
3186 /* Flip the surface data */
3187 {
3188 void* tmp;
3189
3190 tmp = front->dib.bitmap_data;
3191 front->dib.bitmap_data = back->dib.bitmap_data;
3192 back->dib.bitmap_data = tmp;
3193
3194 tmp = front->resource.allocatedMemory;
3195 front->resource.allocatedMemory = back->resource.allocatedMemory;
3196 back->resource.allocatedMemory = tmp;
3197
3198 tmp = front->resource.heapMemory;
3199 front->resource.heapMemory = back->resource.heapMemory;
3200 back->resource.heapMemory = tmp;
3201 }
3202
3203 /* Flip the PBO */
3204 {
3205 GLuint tmp_pbo = front->pbo;
3206 front->pbo = back->pbo;
3207 back->pbo = tmp_pbo;
3208 }
3209
3210 /* client_memory should not be different, but just in case */
3211 {
3212 BOOL tmp;
3213 tmp = front->dib.client_memory;
3214 front->dib.client_memory = back->dib.client_memory;
3215 back->dib.client_memory = tmp;
3216 }
3217
3218 /* Flip the opengl texture */
3219 {
3220 GLuint tmp;
3221
3222 tmp = back->texture_name;
3223 back->texture_name = front->texture_name;
3224 front->texture_name = tmp;
3225
3226 tmp = back->texture_name_srgb;
3227 back->texture_name_srgb = front->texture_name_srgb;
3228 front->texture_name_srgb = tmp;
3229 }
3230
3231 {
3232 DWORD tmp_flags = back->Flags;
3233 back->Flags = front->Flags;
3234 front->Flags = tmp_flags;
3235 }
3236}
3237
3238static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
3239 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
3240 IWineD3DSwapChainImpl *swapchain = NULL;
3241 HRESULT hr;
3242 TRACE("(%p)->(%p,%x)\n", This, override, Flags);
3243
3244 /* Flipping is only supported on RenderTargets and overlays*/
3245 if( !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_OVERLAY)) ) {
3246 WARN("Tried to flip a non-render target, non-overlay surface\n");
3247 return WINEDDERR_NOTFLIPPABLE;
3248 }
3249
3250 if(This->resource.usage & WINED3DUSAGE_OVERLAY) {
3251 flip_surface(This, (IWineD3DSurfaceImpl *) override);
3252
3253 /* Update the overlay if it is visible */
3254 if(This->overlay_dest) {
3255 return IWineD3DSurface_DrawOverlay((IWineD3DSurface *) This);
3256 } else {
3257 return WINED3D_OK;
3258 }
3259 }
3260
3261 if(override) {
3262 /* DDraw sets this for the X11 surfaces, so don't confuse the user
3263 * FIXME("(%p) Target override is not supported by now\n", This);
3264 * Additionally, it isn't really possible to support triple-buffering
3265 * properly on opengl at all
3266 */
3267 }
3268
3269 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **) &swapchain);
3270 if(!swapchain) {
3271 ERR("Flipped surface is not on a swapchain\n");
3272 return WINEDDERR_NOTFLIPPABLE;
3273 }
3274
3275 /* Just overwrite the swapchain presentation interval. This is ok because only ddraw apps can call Flip,
3276 * and only d3d8 and d3d9 apps specify the presentation interval
3277 */
3278 if((Flags & (WINEDDFLIP_NOVSYNC | WINEDDFLIP_INTERVAL2 | WINEDDFLIP_INTERVAL3 | WINEDDFLIP_INTERVAL4)) == 0) {
3279 /* Most common case first to avoid wasting time on all the other cases */
3280 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_ONE;
3281 } else if(Flags & WINEDDFLIP_NOVSYNC) {
3282 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
3283 } else if(Flags & WINEDDFLIP_INTERVAL2) {
3284 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_TWO;
3285 } else if(Flags & WINEDDFLIP_INTERVAL3) {
3286 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_THREE;
3287 } else {
3288 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_FOUR;
3289 }
3290
3291 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
3292 hr = IWineD3DSwapChain_Present((IWineD3DSwapChain *)swapchain,
3293 NULL, NULL, swapchain->win_handle, NULL, 0);
3294
3295 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
3296 return hr;
3297}
3298
3299/* Does a direct frame buffer -> texture copy. Stretching is done
3300 * with single pixel copy calls
3301 */
3302static inline BOOL fb_copy_to_texture_direct(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface,
3303 const RECT *src_rect, const RECT *dst_rect_in, WINED3DTEXTUREFILTERTYPE Filter, BOOL fFastOnly)
3304{
3305 IWineD3DDeviceImpl *myDevice = This->resource.device;
3306 float xrel, yrel;
3307 UINT row;
3308 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
3309 struct wined3d_context *context;
3310 BOOL upsidedown = FALSE;
3311 BOOL isSrcOffscreen = surface_is_offscreen(SrcSurface);
3312 BOOL fNoStretching = TRUE;
3313 RECT dst_rect = *dst_rect_in;
3314
3315 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
3316 * glCopyTexSubImage is a bit picky about the parameters we pass to it
3317 */
3318 if(dst_rect.top > dst_rect.bottom) {
3319 UINT tmp = dst_rect.bottom;
3320#ifdef DEBUG_misha
3321 ERR("validate this path!");
3322#endif
3323 dst_rect.bottom = dst_rect.top;
3324 dst_rect.top = tmp;
3325 upsidedown = TRUE;
3326 }
3327
3328 if (isSrcOffscreen)
3329 {
3330 upsidedown = !upsidedown;
3331 }
3332
3333 xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
3334 yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
3335
3336 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
3337 {
3338 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
3339
3340 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
3341 ERR("Texture filtering not supported in direct blit\n");
3342 }
3343 }
3344 else if ((Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT)
3345 && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
3346 {
3347 ERR("Texture filtering not supported in direct blit\n");
3348 }
3349
3350 fNoStretching = !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
3351 && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps));
3352
3353 if (fFastOnly && (!upsidedown || !fNoStretching))
3354 {
3355 return FALSE;
3356 }
3357
3358 context = context_acquire(myDevice, SrcSurface, CTXUSAGE_BLIT);
3359
3360 surface_internal_preload((IWineD3DSurface *) This, SRGB_RGB);
3361 ENTER_GL();
3362
3363 /* Bind the target texture */
3364 glBindTexture(This->texture_target, This->texture_name);
3365 checkGLcall("glBindTexture");
3366 if(isSrcOffscreen) {
3367 TRACE("Reading from an offscreen target\n");
3368 glReadBuffer(myDevice->offscreenBuffer);
3369 checkGLcall("glReadBuffer()");
3370 }
3371 else
3372 {
3373 glReadBuffer(surface_get_gl_buffer(SrcSurface));
3374 checkGLcall("glReadBuffer()");
3375 }
3376 checkGLcall("glReadBuffer");
3377
3378 if (upsidedown && fNoStretching)
3379 {
3380 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
3381
3382 glCopyTexSubImage2D(This->texture_target, This->texture_level,
3383 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
3384 src_rect->left, src_rect->top,
3385 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
3386 } else {
3387 UINT yoffset = Src->currentDesc.Height - src_rect->top + dst_rect.top - 1;
3388 /* I have to process this row by row to swap the image,
3389 * otherwise it would be upside down, so stretching in y direction
3390 * doesn't cost extra time
3391 *
3392 * However, stretching in x direction can be avoided if not necessary
3393 */
3394
3395 if (fNoStretching)
3396 {
3397 /* No stretching involved, so just pass negative height and let host side take care of inverting */
3398
3399 glCopyTexSubImage2D(This->texture_target, This->texture_level,
3400 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
3401 src_rect->left, Src->currentDesc.Height - src_rect->bottom,
3402 dst_rect.right - dst_rect.left, -(dst_rect.bottom-dst_rect.top));
3403 }
3404 else
3405 {
3406 for(row = dst_rect.top; row < dst_rect.bottom; row++) {
3407 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
3408 {
3409 /* Well, that stuff works, but it's very slow.
3410 * find a better way instead
3411 */
3412 UINT col;
3413
3414 for(col = dst_rect.left; col < dst_rect.right; col++) {
3415 glCopyTexSubImage2D(This->texture_target, This->texture_level,
3416 dst_rect.left + col /* x offset */, row /* y offset */,
3417 src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
3418 }
3419 } else {
3420 glCopyTexSubImage2D(This->texture_target, This->texture_level,
3421 dst_rect.left /* x offset */, row /* y offset */,
3422 src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
3423 }
3424 }
3425 }
3426 }
3427 checkGLcall("glCopyTexSubImage2D");
3428
3429 LEAVE_GL();
3430 context_release(context);
3431
3432 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
3433 * path is never entered
3434 */
3435 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) This, SFLAG_INTEXTURE, TRUE);
3436
3437 return TRUE;
3438}
3439
3440/* Uses the hardware to stretch and flip the image */
3441static inline void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface,
3442 const RECT *src_rect, const RECT *dst_rect_in, WINED3DTEXTUREFILTERTYPE Filter)
3443{
3444 IWineD3DDeviceImpl *myDevice = This->resource.device;
3445 GLuint src, backup = 0;
3446 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
3447 IWineD3DSwapChainImpl *src_swapchain = NULL;
3448 float left, right, top, bottom; /* Texture coordinates */
3449 UINT fbwidth = Src->currentDesc.Width;
3450 UINT fbheight = Src->currentDesc.Height;
3451 struct wined3d_context *context;
3452 GLenum drawBuffer = GL_BACK;
3453 GLenum texture_target;
3454 BOOL noBackBufferBackup;
3455 BOOL src_offscreen;
3456 BOOL upsidedown = FALSE;
3457 RECT dst_rect = *dst_rect_in;
3458
3459 TRACE("Using hwstretch blit\n");
3460 /* Activate the Proper context for reading from the source surface, set it up for blitting */
3461 context = context_acquire(myDevice, SrcSurface, CTXUSAGE_BLIT);
3462 surface_internal_preload((IWineD3DSurface *) This, SRGB_RGB);
3463
3464 src_offscreen = surface_is_offscreen(SrcSurface);
3465 noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
3466 if (!noBackBufferBackup && !Src->texture_name)
3467 {
3468 /* Get it a description */
3469 surface_internal_preload(SrcSurface, SRGB_RGB);
3470 }
3471 ENTER_GL();
3472
3473 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
3474 * This way we don't have to wait for the 2nd readback to finish to leave this function.
3475 */
3476 if (context->aux_buffers >= 2)
3477 {
3478 /* Got more than one aux buffer? Use the 2nd aux buffer */
3479 drawBuffer = GL_AUX1;
3480 }
3481 else if ((!src_offscreen || myDevice->offscreenBuffer == GL_BACK) && context->aux_buffers >= 1)
3482 {
3483 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
3484 drawBuffer = GL_AUX0;
3485 }
3486
3487 if(noBackBufferBackup) {
3488 glGenTextures(1, &backup);
3489 checkGLcall("glGenTextures");
3490 glBindTexture(GL_TEXTURE_2D, backup);
3491 checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
3492 texture_target = GL_TEXTURE_2D;
3493 } else {
3494 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
3495 * we are reading from the back buffer, the backup can be used as source texture
3496 */
3497 texture_target = Src->texture_target;
3498 glBindTexture(texture_target, Src->texture_name);
3499 checkGLcall("glBindTexture(texture_target, Src->texture_name)");
3500 glEnable(texture_target);
3501 checkGLcall("glEnable(texture_target)");
3502
3503 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
3504 Src->Flags &= ~SFLAG_INTEXTURE;
3505 }
3506
3507 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
3508 * glCopyTexSubImage is a bit picky about the parameters we pass to it
3509 */
3510 if(dst_rect.top > dst_rect.bottom) {
3511 UINT tmp = dst_rect.bottom;
3512 dst_rect.bottom = dst_rect.top;
3513 dst_rect.top = tmp;
3514 upsidedown = TRUE;
3515 }
3516
3517 if (src_offscreen)
3518 {
3519 TRACE("Reading from an offscreen target\n");
3520 upsidedown = !upsidedown;
3521 glReadBuffer(myDevice->offscreenBuffer);
3522 }
3523 else
3524 {
3525 glReadBuffer(surface_get_gl_buffer(SrcSurface));
3526 }
3527
3528 /* TODO: Only back up the part that will be overwritten */
3529 glCopyTexSubImage2D(texture_target, 0,
3530 0, 0 /* read offsets */,
3531 0, 0,
3532 fbwidth,
3533 fbheight);
3534
3535 checkGLcall("glCopyTexSubImage2D");
3536
3537 /* No issue with overriding these - the sampler is dirty due to blit usage */
3538 glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER,
3539 wined3d_gl_mag_filter(magLookup, Filter));
3540 checkGLcall("glTexParameteri");
3541 glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
3542 wined3d_gl_min_mip_filter(minMipLookup, Filter, WINED3DTEXF_NONE));
3543 checkGLcall("glTexParameteri");
3544
3545 IWineD3DSurface_GetContainer((IWineD3DSurface *)SrcSurface, &IID_IWineD3DSwapChain, (void **)&src_swapchain);
3546 if (src_swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *)src_swapchain);
3547 if (!src_swapchain || (IWineD3DSurface *) Src == src_swapchain->backBuffer[0]) {
3548 src = backup ? backup : Src->texture_name;
3549 } else {
3550 glReadBuffer(GL_FRONT);
3551 checkGLcall("glReadBuffer(GL_FRONT)");
3552
3553 glGenTextures(1, &src);
3554 checkGLcall("glGenTextures(1, &src)");
3555 glBindTexture(GL_TEXTURE_2D, src);
3556 checkGLcall("glBindTexture(GL_TEXTURE_2D, src)");
3557
3558 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
3559 * out for power of 2 sizes
3560 */
3561 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Src->pow2Width, Src->pow2Height, 0,
3562 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
3563 checkGLcall("glTexImage2D");
3564 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
3565 0, 0 /* read offsets */,
3566 0, 0,
3567 fbwidth,
3568 fbheight);
3569
3570 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3571 checkGLcall("glTexParameteri");
3572 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3573 checkGLcall("glTexParameteri");
3574
3575 glReadBuffer(GL_BACK);
3576 checkGLcall("glReadBuffer(GL_BACK)");
3577
3578 if(texture_target != GL_TEXTURE_2D) {
3579 glDisable(texture_target);
3580 glEnable(GL_TEXTURE_2D);
3581 texture_target = GL_TEXTURE_2D;
3582 }
3583 }
3584 checkGLcall("glEnd and previous");
3585
3586 left = src_rect->left;
3587 right = src_rect->right;
3588
3589 if(upsidedown) {
3590 top = Src->currentDesc.Height - src_rect->top;
3591 bottom = Src->currentDesc.Height - src_rect->bottom;
3592 } else {
3593 top = Src->currentDesc.Height - src_rect->bottom;
3594 bottom = Src->currentDesc.Height - src_rect->top;
3595 }
3596
3597 if(Src->Flags & SFLAG_NORMCOORD) {
3598 left /= Src->pow2Width;
3599 right /= Src->pow2Width;
3600 top /= Src->pow2Height;
3601 bottom /= Src->pow2Height;
3602 }
3603
3604 /* draw the source texture stretched and upside down. The correct surface is bound already */
3605 glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
3606 glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
3607
3608 context_set_draw_buffer(context, drawBuffer);
3609 glReadBuffer(drawBuffer);
3610
3611 glBegin(GL_QUADS);
3612 /* bottom left */
3613 glTexCoord2f(left, bottom);
3614 glVertex2i(0, fbheight);
3615
3616 /* top left */
3617 glTexCoord2f(left, top);
3618 glVertex2i(0, fbheight - (dst_rect.bottom - dst_rect.top));
3619
3620 /* top right */
3621 glTexCoord2f(right, top);
3622 glVertex2i(dst_rect.right - dst_rect.left, fbheight - (dst_rect.bottom - dst_rect.top));
3623
3624 /* bottom right */
3625 glTexCoord2f(right, bottom);
3626 glVertex2i(dst_rect.right - dst_rect.left, fbheight);
3627 glEnd();
3628 checkGLcall("glEnd and previous");
3629
3630 if (texture_target != This->texture_target)
3631 {
3632 glDisable(texture_target);
3633 glEnable(This->texture_target);
3634 texture_target = This->texture_target;
3635 }
3636
3637 /* Now read the stretched and upside down image into the destination texture */
3638 glBindTexture(texture_target, This->texture_name);
3639 checkGLcall("glBindTexture");
3640 glCopyTexSubImage2D(texture_target,
3641 0,
3642 dst_rect.left, dst_rect.top, /* xoffset, yoffset */
3643 0, 0, /* We blitted the image to the origin */
3644 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
3645 checkGLcall("glCopyTexSubImage2D");
3646
3647 if(drawBuffer == GL_BACK) {
3648 /* Write the back buffer backup back */
3649 if(backup) {
3650 if(texture_target != GL_TEXTURE_2D) {
3651 glDisable(texture_target);
3652 glEnable(GL_TEXTURE_2D);
3653 texture_target = GL_TEXTURE_2D;
3654 }
3655 glBindTexture(GL_TEXTURE_2D, backup);
3656 checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
3657 } else {
3658 if (texture_target != Src->texture_target)
3659 {
3660 glDisable(texture_target);
3661 glEnable(Src->texture_target);
3662 texture_target = Src->texture_target;
3663 }
3664 glBindTexture(Src->texture_target, Src->texture_name);
3665 checkGLcall("glBindTexture(Src->texture_target, Src->texture_name)");
3666 }
3667
3668 glBegin(GL_QUADS);
3669 /* top left */
3670 glTexCoord2f(0.0f, (float)fbheight / (float)Src->pow2Height);
3671 glVertex2i(0, 0);
3672
3673 /* bottom left */
3674 glTexCoord2f(0.0f, 0.0f);
3675 glVertex2i(0, fbheight);
3676
3677 /* bottom right */
3678 glTexCoord2f((float)fbwidth / (float)Src->pow2Width, 0.0f);
3679 glVertex2i(fbwidth, Src->currentDesc.Height);
3680
3681 /* top right */
3682 glTexCoord2f((float) fbwidth / (float) Src->pow2Width, (float) fbheight / (float) Src->pow2Height);
3683 glVertex2i(fbwidth, 0);
3684 glEnd();
3685 }
3686 glDisable(texture_target);
3687 checkGLcall("glDisable(texture_target)");
3688
3689 /* Cleanup */
3690 if (src != Src->texture_name && src != backup)
3691 {
3692 glDeleteTextures(1, &src);
3693 checkGLcall("glDeleteTextures(1, &src)");
3694 }
3695 if(backup) {
3696 glDeleteTextures(1, &backup);
3697 checkGLcall("glDeleteTextures(1, &backup)");
3698 }
3699
3700 LEAVE_GL();
3701
3702 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
3703
3704 context_release(context);
3705
3706 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
3707 * path is never entered
3708 */
3709 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) This, SFLAG_INTEXTURE, TRUE);
3710}
3711
3712/* Until the blit_shader is ready, define some prototypes here. */
3713static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum blit_operation blit_op,
3714 const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool,
3715 const struct wined3d_format_desc *src_format_desc,
3716 const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool,
3717 const struct wined3d_format_desc *dst_format_desc);
3718
3719/* Not called from the VTable */
3720static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, const RECT *DestRect,
3721 IWineD3DSurface *SrcSurface, const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx,
3722 WINED3DTEXTUREFILTERTYPE Filter)
3723{
3724 IWineD3DDeviceImpl *myDevice = This->resource.device;
3725 IWineD3DSwapChainImpl *srcSwapchain = NULL, *dstSwapchain = NULL;
3726 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
3727 RECT dst_rect, src_rect;
3728#ifdef VBOX_WITH_WDDM
3729 BOOL fNoRtInvolved = FALSE;
3730#endif
3731
3732 TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
3733
3734 /* Get the swapchain. One of the surfaces has to be a primary surface */
3735 if(This->resource.pool == WINED3DPOOL_SYSTEMMEM) {
3736 WARN("Destination is in sysmem, rejecting gl blt\n");
3737 return WINED3DERR_INVALIDCALL;
3738 }
3739 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&dstSwapchain);
3740 if(dstSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) dstSwapchain);
3741 if(Src) {
3742 if(Src->resource.pool == WINED3DPOOL_SYSTEMMEM) {
3743 WARN("Src is in sysmem, rejecting gl blt\n");
3744 return WINED3DERR_INVALIDCALL;
3745 }
3746 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&srcSwapchain);
3747 if(srcSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) srcSwapchain);
3748 }
3749
3750 /* Early sort out of cases where no render target is used */
3751 if(!dstSwapchain && !srcSwapchain &&
3752 SrcSurface != myDevice->render_targets[0] && This != (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
3753 TRACE("No surface is render target, not using hardware blit. Src = %p, dst = %p\n", Src, This);
3754#ifdef VBOX_WITH_WDDM
3755 fNoRtInvolved = TRUE;
3756#else
3757 return WINED3DERR_INVALIDCALL;
3758#endif
3759 }
3760
3761 /* No destination color keying supported */
3762 if(Flags & (WINEDDBLT_KEYDEST | WINEDDBLT_KEYDESTOVERRIDE)) {
3763 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
3764 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
3765 return WINED3DERR_INVALIDCALL;
3766 }
3767
3768 surface_get_rect(This, DestRect, &dst_rect);
3769 if(Src) surface_get_rect(Src, SrcRect, &src_rect);
3770
3771 /* The only case where both surfaces on a swapchain are supported is a back buffer -> front buffer blit on the same swapchain */
3772 if(dstSwapchain && dstSwapchain == srcSwapchain && dstSwapchain->backBuffer &&
3773 ((IWineD3DSurface *) This == dstSwapchain->frontBuffer) && SrcSurface == dstSwapchain->backBuffer[0]) {
3774#ifdef VBOX_WITH_WDDM
3775 ERR("should never be here!!");
3776#endif
3777 /* Half-life does a Blt from the back buffer to the front buffer,
3778 * Full surface size, no flags... Use present instead
3779 *
3780 * This path will only be entered for d3d7 and ddraw apps, because d3d8/9 offer no way to blit TO the front buffer
3781 */
3782
3783 /* Check rects - IWineD3DDevice_Present doesn't handle them */
3784 while(1)
3785 {
3786 TRACE("Looking if a Present can be done...\n");
3787 /* Source Rectangle must be full surface */
3788 if(src_rect.left != 0 || src_rect.top != 0 ||
3789 src_rect.right != Src->currentDesc.Width || src_rect.bottom != Src->currentDesc.Height) {
3790 TRACE("No, Source rectangle doesn't match\n");
3791 break;
3792 }
3793
3794 /* No stretching may occur */
3795 if(src_rect.right != dst_rect.right - dst_rect.left ||
3796 src_rect.bottom != dst_rect.bottom - dst_rect.top) {
3797 TRACE("No, stretching is done\n");
3798 break;
3799 }
3800
3801 /* Destination must be full surface or match the clipping rectangle */
3802 if(This->clipper && ((IWineD3DClipperImpl *) This->clipper)->hWnd)
3803 {
3804 RECT cliprect;
3805 POINT pos[2];
3806 GetClientRect(((IWineD3DClipperImpl *) This->clipper)->hWnd, &cliprect);
3807 pos[0].x = dst_rect.left;
3808 pos[0].y = dst_rect.top;
3809 pos[1].x = dst_rect.right;
3810 pos[1].y = dst_rect.bottom;
3811 MapWindowPoints(GetDesktopWindow(), ((IWineD3DClipperImpl *) This->clipper)->hWnd,
3812 pos, 2);
3813
3814 if(pos[0].x != cliprect.left || pos[0].y != cliprect.top ||
3815 pos[1].x != cliprect.right || pos[1].y != cliprect.bottom)
3816 {
3817 TRACE("No, dest rectangle doesn't match(clipper)\n");
3818 TRACE("Clip rect at %s\n", wine_dbgstr_rect(&cliprect));
3819 TRACE("Blt dest: %s\n", wine_dbgstr_rect(&dst_rect));
3820 break;
3821 }
3822 }
3823 else
3824 {
3825 if(dst_rect.left != 0 || dst_rect.top != 0 ||
3826 dst_rect.right != This->currentDesc.Width || dst_rect.bottom != This->currentDesc.Height) {
3827 TRACE("No, dest rectangle doesn't match(surface size)\n");
3828 break;
3829 }
3830 }
3831
3832 TRACE("Yes\n");
3833
3834 /* These flags are unimportant for the flag check, remove them */
3835 if((Flags & ~(WINEDDBLT_DONOTWAIT | WINEDDBLT_WAIT)) == 0) {
3836 WINED3DSWAPEFFECT orig_swap = dstSwapchain->presentParms.SwapEffect;
3837
3838 /* The idea behind this is that a glReadPixels and a glDrawPixels call
3839 * take very long, while a flip is fast.
3840 * This applies to Half-Life, which does such Blts every time it finished
3841 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
3842 * menu. This is also used by all apps when they do windowed rendering
3843 *
3844 * The problem is that flipping is not really the same as copying. After a
3845 * Blt the front buffer is a copy of the back buffer, and the back buffer is
3846 * untouched. Therefore it's necessary to override the swap effect
3847 * and to set it back after the flip.
3848 *
3849 * Windowed Direct3D < 7 apps do the same. The D3D7 sdk demos are nice
3850 * testcases.
3851 */
3852
3853 dstSwapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
3854 dstSwapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
3855
3856 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
3857 IWineD3DSwapChain_Present((IWineD3DSwapChain *)dstSwapchain,
3858 NULL, NULL, dstSwapchain->win_handle, NULL, 0);
3859
3860 dstSwapchain->presentParms.SwapEffect = orig_swap;
3861
3862 return WINED3D_OK;
3863 }
3864 break;
3865 }
3866
3867 TRACE("Unsupported blit between buffers on the same swapchain\n");
3868 return WINED3DERR_INVALIDCALL;
3869 } else if(dstSwapchain && dstSwapchain == srcSwapchain) {
3870 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
3871 return WINED3DERR_INVALIDCALL;
3872 } else if(dstSwapchain && srcSwapchain) {
3873 FIXME("Implement hardware blit between two different swapchains\n");
3874 return WINED3DERR_INVALIDCALL;
3875 } else if(dstSwapchain) {
3876 if(SrcSurface == myDevice->render_targets[0]) {
3877 TRACE("Blit from active render target to a swapchain\n");
3878 /* Handled with regular texture -> swapchain blit */
3879 }
3880 } else if(srcSwapchain && This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
3881 FIXME("Implement blit from a swapchain to the active render target\n");
3882 return WINED3DERR_INVALIDCALL;
3883 }
3884
3885 if(
3886#ifdef VBOX_WITH_WDDM
3887 fNoRtInvolved ||
3888#endif
3889 ((srcSwapchain || SrcSurface == myDevice->render_targets[0]) && !dstSwapchain)) {
3890 /* Blit from render target to texture */
3891 BOOL stretchx;
3892
3893 /* P8 read back is not implemented */
3894 if (Src->resource.format_desc->format == WINED3DFMT_P8_UINT ||
3895 This->resource.format_desc->format == WINED3DFMT_P8_UINT)
3896 {
3897 TRACE("P8 read back not supported by frame buffer to texture blit\n");
3898 return WINED3DERR_INVALIDCALL;
3899 }
3900
3901 if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
3902 TRACE("Color keying not supported by frame buffer to texture blit\n");
3903 return WINED3DERR_INVALIDCALL;
3904 /* Destination color key is checked above */
3905 }
3906
3907 if(dst_rect.right - dst_rect.left != src_rect.right - src_rect.left) {
3908 stretchx = TRUE;
3909 } else {
3910 stretchx = FALSE;
3911 }
3912
3913 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
3914 * flip the image nor scale it.
3915 *
3916 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
3917 * -> If the app wants a image width an unscaled width, copy it line per line
3918 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
3919 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
3920 * back buffer. This is slower than reading line per line, thus not used for flipping
3921 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
3922 * pixel by pixel
3923 *
3924 * If EXT_framebuffer_blit is supported that can be used instead. Note that EXT_framebuffer_blit implies
3925 * FBO support, so it doesn't really make sense to try and make it work with different offscreen rendering
3926 * backends.
3927 */
3928 if (fbo_blit_supported(&myDevice->adapter->gl_info, BLIT_OP_BLIT,
3929 &src_rect, Src->resource.usage, Src->resource.pool, Src->resource.format_desc,
3930 &dst_rect, This->resource.usage, This->resource.pool, This->resource.format_desc)
3931 && (!(myDevice->adapter->gl_info.quirks & WINED3D_QUIRK_FULLSIZE_BLIT)
3932 || (dst_rect.right==This->currentDesc.Width && dst_rect.bottom==This->currentDesc.Height
3933 && dst_rect.left==0 && dst_rect.top==0)
3934 )
3935 )
3936 {
3937 /* blit framebuffer might be buggy for some NVIDIA GPUs,
3938 * on the contrary some Intel GPUs fail glCopyTexSubImage2D for some reason,
3939 * check if we can use fb_copy_to_texture_direct and try if it can do it quickly */
3940 if ((myDevice->adapter->gl_info.quirks & WINED3D_QUIRK_FORCE_BLIT)
3941 || !fb_copy_to_texture_direct(This, SrcSurface, &src_rect, &dst_rect, Filter, TRUE /* fast only */))
3942 {
3943 TRACE("fb_copy_to_texture_direct can not do it fast, use stretch_rect_fbo\n");
3944 stretch_rect_fbo((IWineD3DDevice *)myDevice, SrcSurface, &src_rect,
3945 (IWineD3DSurface *)This, &dst_rect, Filter);
3946 }
3947 } else if((!stretchx) || dst_rect.right - dst_rect.left > Src->currentDesc.Width ||
3948 dst_rect.bottom - dst_rect.top > Src->currentDesc.Height) {
3949 TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
3950 fb_copy_to_texture_direct(This, SrcSurface, &src_rect, &dst_rect, Filter, FALSE /* do it always */);
3951 } else {
3952 TRACE("Using hardware stretching to flip / stretch the texture\n");
3953 fb_copy_to_texture_hwstretch(This, SrcSurface, &src_rect, &dst_rect, Filter);
3954 }
3955
3956 if(!(This->Flags & SFLAG_DONOTFREE)) {
3957 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
3958 This->resource.allocatedMemory = NULL;
3959 This->resource.heapMemory = NULL;
3960 } else {
3961 This->Flags &= ~SFLAG_INSYSMEM;
3962 }
3963
3964 return WINED3D_OK;
3965 } else if(Src) {
3966 /* Blit from offscreen surface to render target */
3967 DWORD oldCKeyFlags = Src->CKeyFlags;
3968 WINEDDCOLORKEY oldBltCKey = Src->SrcBltCKey;
3969 struct wined3d_context *context;
3970
3971 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
3972
3973 if (!(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
3974 && fbo_blit_supported(&myDevice->adapter->gl_info, BLIT_OP_BLIT,
3975 &src_rect, Src->resource.usage, Src->resource.pool, Src->resource.format_desc,
3976 &dst_rect, This->resource.usage, This->resource.pool, This->resource.format_desc)
3977 && (!(myDevice->adapter->gl_info.quirks & WINED3D_QUIRK_FULLSIZE_BLIT)
3978 || (dst_rect.right==This->currentDesc.Width && dst_rect.bottom==This->currentDesc.Height
3979 && dst_rect.left==0 && dst_rect.top==0)
3980 )
3981 )
3982 {
3983 TRACE("Using stretch_rect_fbo\n");
3984 /* The source is always a texture, but never the currently active render target, and the texture
3985 * contents are never upside down
3986 */
3987 stretch_rect_fbo((IWineD3DDevice *)myDevice, SrcSurface, &src_rect,
3988 (IWineD3DSurface *)This, &dst_rect, Filter);
3989 return WINED3D_OK;
3990 }
3991
3992 if (!(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
3993 && arbfp_blit.blit_supported(&myDevice->adapter->gl_info, BLIT_OP_BLIT,
3994 &src_rect, Src->resource.usage, Src->resource.pool, Src->resource.format_desc,
3995 &dst_rect, This->resource.usage, This->resource.pool, This->resource.format_desc))
3996 {
3997 return arbfp_blit_surface(myDevice, Src, &src_rect, This, &dst_rect, BLIT_OP_BLIT, Filter);
3998 }
3999
4000 /* Color keying: Check if we have to do a color keyed blt,
4001 * and if not check if a color key is activated.
4002 *
4003 * Just modify the color keying parameters in the surface and restore them afterwards
4004 * The surface keeps track of the color key last used to load the opengl surface.
4005 * PreLoad will catch the change to the flags and color key and reload if necessary.
4006 */
4007 if(Flags & WINEDDBLT_KEYSRC) {
4008 /* Use color key from surface */
4009 } else if(Flags & WINEDDBLT_KEYSRCOVERRIDE) {
4010 /* Use color key from DDBltFx */
4011 Src->CKeyFlags |= WINEDDSD_CKSRCBLT;
4012 Src->SrcBltCKey = DDBltFx->ddckSrcColorkey;
4013 } else {
4014 /* Do not use color key */
4015 Src->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
4016 }
4017
4018 /* Now load the surface */
4019 surface_internal_preload((IWineD3DSurface *) Src, SRGB_RGB);
4020
4021 /* Activate the destination context, set it up for blitting */
4022 context = context_acquire(myDevice, (IWineD3DSurface *)This, CTXUSAGE_BLIT);
4023
4024 /* The coordinates of the ddraw front buffer are always fullscreen ('screen coordinates',
4025 * while OpenGL coordinates are window relative.
4026 * Also beware of the origin difference(top left vs bottom left).
4027 * Also beware that the front buffer's surface size is screen width x screen height,
4028 * whereas the real gl drawable size is the size of the window.
4029 */
4030 if (dstSwapchain && (IWineD3DSurface *)This == dstSwapchain->frontBuffer) {
4031#ifndef VBOX_WITH_WDDM
4032 RECT windowsize;
4033 POINT offset = {0,0};
4034 UINT h;
4035#ifdef VBOX_WITH_WDDM
4036 HWND hWnd = context->currentSwapchain->win_handle;
4037 ClientToScreen(hWnd, &offset);
4038 GetClientRect(hWnd, &windowsize);
4039#else
4040 ClientToScreen(context->win_handle, &offset);
4041 GetClientRect(context->win_handle, &windowsize);
4042#endif
4043 h = windowsize.bottom - windowsize.top;
4044 dst_rect.left -= offset.x; dst_rect.right -=offset.x;
4045 dst_rect.top -= offset.y; dst_rect.bottom -=offset.y;
4046 dst_rect.top += This->currentDesc.Height - h; dst_rect.bottom += This->currentDesc.Height - h;
4047#endif
4048 }
4049 else if (surface_is_offscreen((IWineD3DSurface *)This))
4050 {
4051 dst_rect.top = This->currentDesc.Height-dst_rect.top;
4052 dst_rect.bottom = This->currentDesc.Height-dst_rect.bottom;
4053 }
4054
4055 if (!myDevice->blitter->blit_supported(&myDevice->adapter->gl_info, BLIT_OP_BLIT,
4056 &src_rect, Src->resource.usage, Src->resource.pool, Src->resource.format_desc,
4057 &dst_rect, This->resource.usage, This->resource.pool, This->resource.format_desc))
4058 {
4059 FIXME("Unsupported blit operation falling back to software\n");
4060 return WINED3DERR_INVALIDCALL;
4061 }
4062
4063 myDevice->blitter->set_shader((IWineD3DDevice *) myDevice, Src);
4064
4065 ENTER_GL();
4066
4067 /* This is for color keying */
4068 if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
4069 glEnable(GL_ALPHA_TEST);
4070 checkGLcall("glEnable(GL_ALPHA_TEST)");
4071
4072 /* When the primary render target uses P8, the alpha component contains the palette index.
4073 * Which means that the colorkey is one of the palette entries. In other cases pixels that
4074 * should be masked away have alpha set to 0. */
4075 if(primary_render_target_is_p8(myDevice))
4076 glAlphaFunc(GL_NOTEQUAL, (float)Src->SrcBltCKey.dwColorSpaceLowValue / 256.0f);
4077 else
4078 glAlphaFunc(GL_NOTEQUAL, 0.0f);
4079 checkGLcall("glAlphaFunc");
4080 } else {
4081 glDisable(GL_ALPHA_TEST);
4082 checkGLcall("glDisable(GL_ALPHA_TEST)");
4083 }
4084
4085 /* Draw a textured quad
4086 */
4087 draw_textured_quad(Src, &src_rect, &dst_rect, Filter);
4088
4089 if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
4090 glDisable(GL_ALPHA_TEST);
4091 checkGLcall("glDisable(GL_ALPHA_TEST)");
4092 }
4093
4094 /* Restore the color key parameters */
4095 Src->CKeyFlags = oldCKeyFlags;
4096 Src->SrcBltCKey = oldBltCKey;
4097
4098 LEAVE_GL();
4099
4100 /* Leave the opengl state valid for blitting */
4101 myDevice->blitter->unset_shader((IWineD3DDevice *) myDevice);
4102
4103 if (wined3d_settings.strict_draw_ordering || (dstSwapchain
4104 && ((IWineD3DSurface *)This == dstSwapchain->frontBuffer
4105#ifdef VBOX_WITH_WDDM
4106 || dstSwapchain->device->numContexts > 1
4107#else
4108 || dstSwapchain->num_contexts > 1
4109#endif
4110 )))
4111 wglFlush(); /* Flush to ensure ordering across contexts. */
4112
4113 context_release(context);
4114
4115 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
4116 /* The surface is now in the drawable. On onscreen surfaces or without fbos the texture
4117 * is outdated now
4118 */
4119 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) This, SFLAG_INDRAWABLE, TRUE);
4120
4121 return WINED3D_OK;
4122 } else {
4123 /* Source-Less Blit to render target */
4124 if (Flags & WINEDDBLT_COLORFILL) {
4125 DWORD color;
4126
4127 TRACE("Colorfill\n");
4128
4129 /* The color as given in the Blt function is in the format of the frame-buffer...
4130 * 'clear' expect it in ARGB format => we need to do some conversion :-)
4131 */
4132 if (!surface_convert_color_to_argb(This, DDBltFx->u5.dwFillColor, &color))
4133 {
4134 /* The color conversion function already prints an error, so need to do it here */
4135 return WINED3DERR_INVALIDCALL;
4136 }
4137
4138 if (ffp_blit.blit_supported(&myDevice->adapter->gl_info, BLIT_OP_COLOR_FILL,
4139 NULL, 0, 0, NULL,
4140 &dst_rect, This->resource.usage, This->resource.pool, This->resource.format_desc))
4141 {
4142 return ffp_blit.color_fill(myDevice, This, &dst_rect, color);
4143 }
4144 else if (cpu_blit.blit_supported(&myDevice->adapter->gl_info, BLIT_OP_COLOR_FILL,
4145 NULL, 0, 0, NULL,
4146 &dst_rect, This->resource.usage, This->resource.pool, This->resource.format_desc))
4147 {
4148 return cpu_blit.color_fill(myDevice, This, &dst_rect, color);
4149 }
4150 return WINED3DERR_INVALIDCALL;
4151 }
4152 }
4153
4154 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
4155 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
4156 return WINED3DERR_INVALIDCALL;
4157}
4158
4159static HRESULT IWineD3DSurfaceImpl_BltZ(IWineD3DSurfaceImpl *This, const RECT *DestRect,
4160 IWineD3DSurface *SrcSurface, const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx)
4161{
4162 IWineD3DDeviceImpl *myDevice = This->resource.device;
4163 float depth;
4164
4165 if (Flags & WINEDDBLT_DEPTHFILL) {
4166 switch(This->resource.format_desc->format)
4167 {
4168 case WINED3DFMT_D16_UNORM:
4169 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0x0000ffff;
4170 break;
4171 case WINED3DFMT_S1_UINT_D15_UNORM:
4172 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0x0000fffe;
4173 break;
4174 case WINED3DFMT_D24_UNORM_S8_UINT:
4175 case WINED3DFMT_X8D24_UNORM:
4176 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0x00ffffff;
4177 break;
4178 case WINED3DFMT_D32_UNORM:
4179 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0xffffffff;
4180 break;
4181 default:
4182 depth = 0.0f;
4183 ERR("Unexpected format for depth fill: %s\n", debug_d3dformat(This->resource.format_desc->format));
4184 }
4185
4186 return IWineD3DDevice_Clear((IWineD3DDevice *) myDevice,
4187 DestRect == NULL ? 0 : 1,
4188 (const WINED3DRECT *)DestRect,
4189 WINED3DCLEAR_ZBUFFER,
4190 0x00000000,
4191 depth,
4192 0x00000000);
4193 }
4194
4195 FIXME("(%p): Unsupp depthstencil blit\n", This);
4196 return WINED3DERR_INVALIDCALL;
4197}
4198
4199#ifdef VBOX_WITH_WDDM
4200/* Not called from the VTable */
4201static HRESULT IWineD3DSurfaceImpl_BltSys2Vram(IWineD3DSurfaceImpl *This, const RECT *DestRect,
4202 IWineD3DSurface *SrcSurface, const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx,
4203 WINED3DTEXTUREFILTERTYPE Filter)
4204{
4205 IWineD3DDeviceImpl *myDevice = This->resource.device;
4206 const struct wined3d_gl_info *gl_info = &myDevice->adapter->gl_info;
4207 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
4208 RECT dst_rect, src_rect;
4209 struct wined3d_format_desc desc;
4210 CONVERT_TYPES convert;
4211 struct wined3d_context *context = NULL;
4212 BYTE *mem;
4213 BYTE *updateMem;
4214 BOOL srgb;
4215 int srcWidth, srcPitch;
4216
4217 TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
4218
4219 if(This->Flags & SFLAG_INSYSMEM) {
4220 WARN("Destination has a SYSMEM location valid, rejecting gl blt\n");
4221 return WINED3DERR_INVALIDCALL;
4222 }
4223
4224 if(!(This->Flags & SFLAG_INTEXTURE)
4225 && !(This->Flags & SFLAG_INSRGBTEX)) {
4226 WARN("Destination does NOT have a TEXTURE location valid, rejecting gl blt\n");
4227 return WINED3DERR_INVALIDCALL;
4228 }
4229
4230 srgb = !(This->Flags & SFLAG_INTEXTURE);
4231
4232 if(!(Src->Flags & SFLAG_INSYSMEM)) {
4233 WARN("Source does NOT have a SYSMEM location valid, rejecting gl blt\n");
4234 return WINED3DERR_INVALIDCALL;
4235 }
4236
4237 if(This->resource.format_desc != Src->resource.format_desc) {
4238 WARN("Src and Dest Formats NOT equal, rejecting gl blt\n");
4239 return WINED3DERR_INVALIDCALL;
4240 }
4241
4242 /* No destination color keying supported */
4243 if(Flags & (WINEDDBLT_KEYDEST | WINEDDBLT_KEYDESTOVERRIDE)) {
4244 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
4245 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
4246 return WINED3DERR_INVALIDCALL;
4247 }
4248
4249 surface_get_rect(This, DestRect, &dst_rect);
4250 surface_get_rect(Src, SrcRect, &src_rect);
4251
4252 if (src_rect.right - src_rect.left != dst_rect.right - dst_rect.left
4253 || src_rect.bottom - src_rect.top != dst_rect.bottom - dst_rect.top)
4254 {
4255 WARN("Stretching requested, rejecting gl blt\n");
4256 return WINED3DERR_INVALIDCALL;
4257 }
4258
4259 if ((Src->Flags & SFLAG_PBO) && src_rect.right - src_rect.left != Src->currentDesc.Width)
4260 {
4261 WARN("Chromium does not support nondefault unpack row length for PBO\n");
4262 return WINED3DERR_INVALIDCALL;
4263 }
4264
4265 d3dfmt_get_conv(Src, TRUE /* We need color keying */, TRUE /* We will use textures */,
4266 &desc, &convert);
4267
4268 if (desc.convert || convert != NO_CONVERSION)
4269 {
4270 WARN("TODO: test if conversion works, rejecting gl blt\n");
4271 return WINED3DERR_INVALIDCALL;
4272 }
4273
4274 if((convert != NO_CONVERSION) && (Src->Flags & SFLAG_PBO)) {
4275 WARN("conversion not supported here with PBO for src %p\n", Src);
4276 return WINED3DERR_INVALIDCALL;
4277 }
4278
4279 if (!myDevice->isInDraw) context = context_acquire(myDevice, NULL, CTXUSAGE_RESOURCELOAD);
4280
4281 surface_bind_and_dirtify(This, srgb);
4282
4283 if(This->CKeyFlags & WINEDDSD_CKSRCBLT) {
4284 This->Flags |= SFLAG_GLCKEY;
4285 This->glCKey = This->SrcBltCKey;
4286 }
4287 else This->Flags &= ~SFLAG_GLCKEY;
4288
4289// /* The width is in 'length' not in bytes */
4290 srcWidth = Src->currentDesc.Width;
4291 srcPitch = IWineD3DSurface_GetPitch(SrcSurface);
4292
4293 if(desc.convert) {
4294 /* This code is entered for texture formats which need a fixup. */
4295 int srcHeight = Src->currentDesc.Height;
4296// int width = Src->currentDesc.Width;
4297// int pitch = IWineD3DSurface_GetPitch(SrcSurface);
4298
4299 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
4300 int outpitch = srcWidth * desc.conv_byte_count;
4301 outpitch = (outpitch + myDevice->surface_alignment - 1) & ~(myDevice->surface_alignment - 1);
4302
4303 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * srcHeight);
4304 if(!mem) {
4305 ERR("Out of memory %d, %d!\n", outpitch, srcHeight);
4306 if (context) context_release(context);
4307 return WINED3DERR_OUTOFVIDEOMEMORY;
4308 }
4309 desc.convert(Src->resource.allocatedMemory, mem, srcPitch, srcWidth, srcHeight);
4310 } else if((convert != NO_CONVERSION) && Src->resource.allocatedMemory) {
4311 /* This code is only entered for color keying fixups */
4312 int srcHeight = Src->currentDesc.Height;
4313 int outpitch;
4314// int width = Src->currentDesc.Width;
4315// int pitch = IWineD3DSurface_GetPitch(SrcSurface);
4316
4317 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
4318 outpitch = srcWidth * desc.conv_byte_count;
4319 outpitch = (outpitch + myDevice->surface_alignment - 1) & ~(myDevice->surface_alignment - 1);
4320
4321 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * srcHeight);
4322 if(!mem) {
4323 ERR("Out of memory %d, %d!\n", outpitch, srcHeight);
4324 if (context) context_release(context);
4325 return WINED3DERR_OUTOFVIDEOMEMORY;
4326 }
4327 d3dfmt_convert_surface(Src->resource.allocatedMemory, mem, srcPitch, srcWidth, srcHeight, outpitch, convert, Src);
4328 } else {
4329 mem = Src->resource.allocatedMemory;
4330 }
4331
4332 updateMem = mem + srcPitch * src_rect.top;
4333
4334 /* Make sure the correct pitch is used */
4335 ENTER_GL();
4336 glPixelStorei(GL_UNPACK_ROW_LENGTH, Src->currentDesc.Width);
4337 glPixelStorei(GL_UNPACK_SKIP_PIXELS, src_rect.left);
4338 LEAVE_GL();
4339
4340 Assert(!!mem == !(Src->Flags & SFLAG_PBO));
4341 surface_upload_data_rect(This, Src, gl_info, &desc, srgb, updateMem, &dst_rect);
4342
4343 /* Restore the default pitch */
4344 ENTER_GL();
4345 glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
4346 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
4347 LEAVE_GL();
4348
4349 if (context) context_release(context);
4350
4351 /* Don't delete PBO memory */
4352 if((mem != Src->resource.allocatedMemory) && !(Src->Flags & SFLAG_PBO))
4353 HeapFree(GetProcessHeap(), 0, mem);
4354 ////
4355
4356 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)This, srgb ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE, TRUE);
4357
4358 return WINED3D_OK;
4359}
4360#endif
4361
4362static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *SrcSurface,
4363 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter) {
4364 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
4365 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
4366 IWineD3DDeviceImpl *myDevice = This->resource.device;
4367 HRESULT hr = WINED3D_OK;
4368
4369 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
4370 TRACE("(%p): Usage is %s\n", This, debug_d3dusage(This->resource.usage));
4371
4372 if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
4373 {
4374 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
4375 return WINEDDERR_SURFACEBUSY;
4376 }
4377
4378#ifdef VBOX_WITH_WDDM
4379 surface_shrc_lock(This);
4380 if (Src) surface_shrc_lock(Src);
4381#endif
4382
4383 /* Accessing the depth stencil is supposed to fail between a BeginScene and EndScene pair,
4384 * except depth blits, which seem to work
4385 */
4386 if(iface == myDevice->stencilBufferTarget || (SrcSurface && SrcSurface == myDevice->stencilBufferTarget)) {
4387 if(myDevice->inScene && !(Flags & WINEDDBLT_DEPTHFILL)) {
4388 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
4389 hr = WINED3DERR_INVALIDCALL;
4390 goto end;
4391 } else if(IWineD3DSurfaceImpl_BltZ(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) {
4392 TRACE("Z Blit override handled the blit\n");
4393 hr = WINED3D_OK;
4394 goto end;
4395 }
4396 }
4397
4398#ifndef VBOX_WITH_WDDM
4399 /* Special cases for RenderTargets */
4400 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
4401 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) ))
4402#endif
4403 {
4404 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx, Filter) == WINED3D_OK)
4405 {
4406 hr = WINED3D_OK;
4407 goto end;
4408 }
4409 }
4410
4411#ifdef VBOX_WITH_WDDM
4412 if (SrcSurface && IWineD3DSurfaceImpl_BltSys2Vram(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx, Filter) == WINED3D_OK)
4413 {
4414 hr = WINED3D_OK;
4415 goto end;
4416 }
4417#endif
4418
4419 /* For the rest call the X11 surface implementation.
4420 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
4421 * other Blts are rather rare
4422 */
4423 hr = IWineD3DBaseSurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx, Filter);
4424end:
4425#ifdef VBOX_WITH_WDDM
4426 surface_shrc_unlock(This);
4427 if (Src) surface_shrc_unlock(Src);
4428#endif
4429 return hr;
4430}
4431
4432static HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
4433 IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
4434{
4435 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
4436 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
4437 IWineD3DDeviceImpl *myDevice = This->resource.device;
4438 HRESULT hr = WINED3D_OK;
4439
4440 TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface, dstx, dsty, Source, rsrc, trans);
4441
4442 if ( (This->Flags & SFLAG_LOCKED) || (srcImpl->Flags & SFLAG_LOCKED))
4443 {
4444 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
4445 return WINEDDERR_SURFACEBUSY;
4446 }
4447
4448 if(myDevice->inScene &&
4449 (iface == myDevice->stencilBufferTarget ||
4450 (Source == myDevice->stencilBufferTarget))) {
4451 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
4452 return WINED3DERR_INVALIDCALL;
4453 }
4454
4455#ifdef VBOX_WITH_WDDM
4456 surface_shrc_lock(This);
4457 surface_shrc_lock(srcImpl);
4458#endif
4459
4460 /* Special cases for RenderTargets */
4461 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
4462 (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
4463
4464 RECT SrcRect, DstRect;
4465 DWORD Flags=0;
4466
4467 surface_get_rect(srcImpl, rsrc, &SrcRect);
4468
4469 DstRect.left = dstx;
4470 DstRect.top=dsty;
4471 DstRect.right = dstx + SrcRect.right - SrcRect.left;
4472 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
4473
4474 /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
4475 if(trans & WINEDDBLTFAST_SRCCOLORKEY)
4476 Flags |= WINEDDBLT_KEYSRC;
4477 if(trans & WINEDDBLTFAST_DESTCOLORKEY)
4478 Flags |= WINEDDBLT_KEYDEST;
4479 if(trans & WINEDDBLTFAST_WAIT)
4480 Flags |= WINEDDBLT_WAIT;
4481 if(trans & WINEDDBLTFAST_DONOTWAIT)
4482 Flags |= WINEDDBLT_DONOTWAIT;
4483
4484 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, Flags, NULL, WINED3DTEXF_POINT) == WINED3D_OK)
4485 {
4486 hr = WINED3D_OK;
4487 goto end;
4488 }
4489 }
4490
4491#if 0 /*@todo: def VBOX_WITH_WDDM*/
4492 if (IWineD3DSurfaceImpl_BltSys2Vram(This, &DstRect, Source, &SrcRect, Flags, NULL, WINED3DTEXF_POINT) == WINED3D_OK)
4493 {
4494 hr = WINED3D_OK;
4495 goto end;
4496 }
4497#endif
4498
4499 hr = IWineD3DBaseSurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
4500end:
4501#ifdef VBOX_WITH_WDDM
4502 surface_shrc_unlock(This);
4503 surface_shrc_unlock(srcImpl);
4504#endif
4505 return hr;
4506}
4507
4508static HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface)
4509{
4510 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
4511 RGBQUAD col[256];
4512 IWineD3DPaletteImpl *pal = This->palette;
4513 unsigned int n;
4514 TRACE("(%p)\n", This);
4515
4516 if (!pal) return WINED3D_OK;
4517
4518 if (This->resource.format_desc->format == WINED3DFMT_P8_UINT
4519 || This->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM)
4520 {
4521 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
4522 {
4523 /* Make sure the texture is up to date. This call doesn't do anything if the texture is already up to date. */
4524 IWineD3DSurface_LoadLocation(iface, SFLAG_INTEXTURE, NULL);
4525
4526 /* We want to force a palette refresh, so mark the drawable as not being up to date */
4527 IWineD3DSurface_ModifyLocation(iface, SFLAG_INDRAWABLE, FALSE);
4528 } else {
4529 if(!(This->Flags & SFLAG_INSYSMEM)) {
4530 TRACE("Palette changed with surface that does not have an up to date system memory copy\n");
4531 IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL);
4532 }
4533 TRACE("Dirtifying surface\n");
4534 IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE);
4535 }
4536 }
4537
4538 if(This->Flags & SFLAG_DIBSECTION) {
4539 TRACE("(%p): Updating the hdc's palette\n", This);
4540 for (n=0; n<256; n++) {
4541 col[n].rgbRed = pal->palents[n].peRed;
4542 col[n].rgbGreen = pal->palents[n].peGreen;
4543 col[n].rgbBlue = pal->palents[n].peBlue;
4544 col[n].rgbReserved = 0;
4545 }
4546 SetDIBColorTable(This->hDC, 0, 256, col);
4547 }
4548
4549 /* Propagate the changes to the drawable when we have a palette. */
4550 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
4551 IWineD3DSurface_LoadLocation(iface, SFLAG_INDRAWABLE, NULL);
4552
4553 return WINED3D_OK;
4554}
4555
4556#ifdef VBOX_WITH_WDDM
4557static HRESULT WINAPI IWineD3DSurfaceImpl_LoadLocation(IWineD3DSurface *iface, DWORD flag, const RECT *rect);
4558#endif
4559
4560static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
4561 /** Check against the maximum texture sizes supported by the video card **/
4562 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
4563 const struct wined3d_gl_info *gl_info = &This->resource.device->adapter->gl_info;
4564 unsigned int pow2Width, pow2Height;
4565
4566 This->texture_name = 0;
4567 This->texture_target = GL_TEXTURE_2D;
4568
4569 /* Non-power2 support */
4570 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[WINE_NORMALIZED_TEXRECT])
4571 {
4572 pow2Width = This->currentDesc.Width;
4573 pow2Height = This->currentDesc.Height;
4574 }
4575 else
4576 {
4577 /* Find the nearest pow2 match */
4578 pow2Width = pow2Height = 1;
4579 while (pow2Width < This->currentDesc.Width) pow2Width <<= 1;
4580 while (pow2Height < This->currentDesc.Height) pow2Height <<= 1;
4581 }
4582 This->pow2Width = pow2Width;
4583 This->pow2Height = pow2Height;
4584
4585 if (pow2Width > This->currentDesc.Width || pow2Height > This->currentDesc.Height) {
4586 /** TODO: add support for non power two compressed textures **/
4587 if (This->resource.format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
4588 {
4589 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
4590 This, This->currentDesc.Width, This->currentDesc.Height);
4591 return WINED3DERR_NOTAVAILABLE;
4592 }
4593 }
4594
4595 if(pow2Width != This->currentDesc.Width ||
4596 pow2Height != This->currentDesc.Height) {
4597 This->Flags |= SFLAG_NONPOW2;
4598 }
4599
4600 TRACE("%p\n", This);
4601 if ((This->pow2Width > gl_info->limits.texture_size || This->pow2Height > gl_info->limits.texture_size)
4602 && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
4603 {
4604 /* one of three options
4605 1: Do the same as we do with nonpow 2 and scale the texture, (any texture ops would require the texture to be scaled which is potentially slow)
4606 2: Set the texture to the maximum size (bad idea)
4607 3: WARN and return WINED3DERR_NOTAVAILABLE;
4608 4: Create the surface, but allow it to be used only for DirectDraw Blts. Some apps(e.g. Swat 3) create textures with a Height of 16 and a Width > 3000 and blt 16x16 letter areas from them to the render target.
4609 */
4610 if(This->resource.pool == WINED3DPOOL_DEFAULT || This->resource.pool == WINED3DPOOL_MANAGED)
4611 {
4612 WARN("(%p) Unable to allocate a surface which exceeds the maximum OpenGL texture size\n", This);
4613 return WINED3DERR_NOTAVAILABLE;
4614 }
4615
4616 /* We should never use this surface in combination with OpenGL! */
4617 TRACE("(%p) Creating an oversized surface: %ux%u\n", This, This->pow2Width, This->pow2Height);
4618 }
4619 else
4620 {
4621 /* Don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
4622 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
4623 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
4624 */
4625 if (This->Flags & SFLAG_NONPOW2 && gl_info->supported[ARB_TEXTURE_RECTANGLE]
4626 && !(This->resource.format_desc->format == WINED3DFMT_P8_UINT
4627 && gl_info->supported[EXT_PALETTED_TEXTURE]
4628 && wined3d_settings.rendertargetlock_mode == RTL_READTEX))
4629 {
4630 This->texture_target = GL_TEXTURE_RECTANGLE_ARB;
4631 This->pow2Width = This->currentDesc.Width;
4632 This->pow2Height = This->currentDesc.Height;
4633 This->Flags &= ~(SFLAG_NONPOW2 | SFLAG_NORMCOORD);
4634 }
4635 }
4636
4637 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
4638 switch(wined3d_settings.offscreen_rendering_mode) {
4639 case ORM_FBO: This->get_drawable_size = get_drawable_size_fbo; break;
4640 case ORM_BACKBUFFER: This->get_drawable_size = get_drawable_size_backbuffer; break;
4641 }
4642 }
4643
4644 This->Flags |= SFLAG_INSYSMEM;
4645
4646 return WINED3D_OK;
4647}
4648
4649/* GL locking is done by the caller */
4650static void surface_depth_blt(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info,
4651 GLuint texture, GLsizei w, GLsizei h, GLenum target)
4652{
4653 IWineD3DDeviceImpl *device = This->resource.device;
4654 struct blt_info info;
4655 GLint old_binding = 0;
4656
4657 glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
4658
4659 glDisable(GL_CULL_FACE);
4660 glDisable(GL_BLEND);
4661 glDisable(GL_ALPHA_TEST);
4662 glDisable(GL_SCISSOR_TEST);
4663 glDisable(GL_STENCIL_TEST);
4664 glEnable(GL_DEPTH_TEST);
4665 glDepthFunc(GL_ALWAYS);
4666 glDepthMask(GL_TRUE);
4667 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
4668 glViewport(0, 0, w, h);
4669
4670 surface_get_blt_info(target, NULL, w, h, &info);
4671 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
4672 glGetIntegerv(info.binding, &old_binding);
4673 glBindTexture(info.bind_target, texture);
4674
4675 device->shader_backend->shader_select_depth_blt((IWineD3DDevice *)device, info.tex_type);
4676
4677 glBegin(GL_TRIANGLE_STRIP);
4678 glTexCoord3fv(info.coords[0]);
4679 glVertex2f(-1.0f, -1.0f);
4680 glTexCoord3fv(info.coords[1]);
4681 glVertex2f(1.0f, -1.0f);
4682 glTexCoord3fv(info.coords[2]);
4683 glVertex2f(-1.0f, 1.0f);
4684 glTexCoord3fv(info.coords[3]);
4685 glVertex2f(1.0f, 1.0f);
4686 glEnd();
4687
4688 glBindTexture(info.bind_target, old_binding);
4689
4690 glPopAttrib();
4691
4692 device->shader_backend->shader_deselect_depth_blt((IWineD3DDevice *)device);
4693}
4694
4695void surface_modify_ds_location(IWineD3DSurface *iface, DWORD location) {
4696 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
4697
4698 TRACE("(%p) New location %#x\n", This, location);
4699
4700 if (location & ~SFLAG_DS_LOCATIONS) {
4701 FIXME("(%p) Invalid location (%#x) specified\n", This, location);
4702 }
4703
4704 This->Flags &= ~SFLAG_DS_LOCATIONS;
4705 This->Flags |= location;
4706}
4707
4708/* Context activation is done by the caller. */
4709void surface_load_ds_location(IWineD3DSurface *iface, struct wined3d_context *context, DWORD location)
4710{
4711 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
4712 IWineD3DDeviceImpl *device = This->resource.device;
4713 const struct wined3d_gl_info *gl_info = context->gl_info;
4714
4715 TRACE("(%p) New location %#x\n", This, location);
4716
4717 /* TODO: Make this work for modes other than FBO */
4718 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
4719
4720 if (This->Flags & location) {
4721 TRACE("(%p) Location (%#x) is already up to date\n", This, location);
4722 return;
4723 }
4724
4725 if (This->current_renderbuffer) {
4726 FIXME("(%p) Not supported with fixed up depth stencil\n", This);
4727 return;
4728 }
4729
4730 if (location == SFLAG_DS_OFFSCREEN) {
4731 if (This->Flags & SFLAG_DS_ONSCREEN) {
4732 GLint old_binding = 0;
4733 GLenum bind_target;
4734
4735 TRACE("(%p) Copying onscreen depth buffer to depth texture\n", This);
4736
4737 ENTER_GL();
4738
4739 if (!device->depth_blt_texture) {
4740 glGenTextures(1, &device->depth_blt_texture);
4741 }
4742
4743 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
4744 * directly on the FBO texture. That's because we need to flip. */
4745 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
4746 if (This->texture_target == GL_TEXTURE_RECTANGLE_ARB)
4747 {
4748 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
4749 bind_target = GL_TEXTURE_RECTANGLE_ARB;
4750 } else {
4751 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
4752 bind_target = GL_TEXTURE_2D;
4753 }
4754 glBindTexture(bind_target, device->depth_blt_texture);
4755 glCopyTexImage2D(bind_target, This->texture_level, This->resource.format_desc->glInternal,
4756 0, 0, This->currentDesc.Width, This->currentDesc.Height, 0);
4757 glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
4758 glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
4759 glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
4760 glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
4761 glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
4762 glTexParameteri(bind_target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
4763 glBindTexture(bind_target, old_binding);
4764
4765 /* Setup the destination */
4766 if (!device->depth_blt_rb) {
4767 gl_info->fbo_ops.glGenRenderbuffers(1, &device->depth_blt_rb);
4768 checkGLcall("glGenRenderbuffersEXT");
4769 }
4770 if (device->depth_blt_rb_w != This->currentDesc.Width
4771 || device->depth_blt_rb_h != This->currentDesc.Height) {
4772 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, device->depth_blt_rb);
4773 checkGLcall("glBindRenderbufferEXT");
4774 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8,
4775 This->currentDesc.Width, This->currentDesc.Height);
4776 checkGLcall("glRenderbufferStorageEXT");
4777 device->depth_blt_rb_w = This->currentDesc.Width;
4778 device->depth_blt_rb_h = This->currentDesc.Height;
4779 }
4780
4781 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
4782 gl_info->fbo_ops.glFramebufferRenderbuffer(GL_FRAMEBUFFER,
4783 GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, device->depth_blt_rb);
4784 checkGLcall("glFramebufferRenderbufferEXT");
4785 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, This, FALSE);
4786
4787 /* Do the actual blit */
4788 surface_depth_blt(This, gl_info, device->depth_blt_texture,
4789 This->currentDesc.Width, This->currentDesc.Height, bind_target);
4790 checkGLcall("depth_blt");
4791
4792 if (context->current_fbo) context_bind_fbo(context, GL_FRAMEBUFFER, &context->current_fbo->id);
4793 else context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
4794
4795 LEAVE_GL();
4796
4797 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
4798 }
4799 else
4800 {
4801 FIXME("No up to date depth stencil location\n");
4802 }
4803 } else if (location == SFLAG_DS_ONSCREEN) {
4804 if (This->Flags & SFLAG_DS_OFFSCREEN) {
4805 TRACE("(%p) Copying depth texture to onscreen depth buffer\n", This);
4806
4807 ENTER_GL();
4808
4809 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
4810 surface_depth_blt(This, gl_info, This->texture_name,
4811 This->currentDesc.Width, This->currentDesc.Height, This->texture_target);
4812 checkGLcall("depth_blt");
4813
4814 if (context->current_fbo) context_bind_fbo(context, GL_FRAMEBUFFER, &context->current_fbo->id);
4815
4816 LEAVE_GL();
4817
4818 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
4819 }
4820 else
4821 {
4822 FIXME("No up to date depth stencil location\n");
4823 }
4824 } else {
4825 ERR("(%p) Invalid location (%#x) specified\n", This, location);
4826 }
4827
4828 This->Flags |= location;
4829}
4830
4831static void WINAPI IWineD3DSurfaceImpl_ModifyLocation(IWineD3DSurface *iface, DWORD flag, BOOL persistent) {
4832 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
4833 IWineD3DBaseTexture *texture;
4834 IWineD3DSurfaceImpl *overlay;
4835
4836 TRACE("(%p)->(%s, %s)\n", iface, debug_surflocation(flag),
4837 persistent ? "TRUE" : "FALSE");
4838
4839 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4840 if (surface_is_offscreen(iface))
4841 {
4842 /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets. */
4843 if (flag & (SFLAG_INTEXTURE | SFLAG_INDRAWABLE)) flag |= (SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
4844 }
4845 else
4846 {
4847 TRACE("Surface %p is an onscreen surface\n", iface);
4848 }
4849 }
4850
4851 if(persistent) {
4852 if(((This->Flags & SFLAG_INTEXTURE) && !(flag & SFLAG_INTEXTURE)) ||
4853 ((This->Flags & SFLAG_INSRGBTEX) && !(flag & SFLAG_INSRGBTEX))) {
4854 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&texture) == WINED3D_OK) {
4855 TRACE("Passing to container\n");
4856 IWineD3DBaseTexture_SetDirty(texture, TRUE);
4857 IWineD3DBaseTexture_Release(texture);
4858 }
4859 }
4860
4861#ifdef VBOX_WITH_WDDM
4862 {
4863 /* sometimes wine can call ModifyLocation(SFLAG_INTEXTURE, TRUE) for surfaces that do not yet have
4864 * ogl texture backend assigned, e.g. when doing ColorFill right after surface creation
4865 * to prevent wine state breakage that could occur later on in that case, we check
4866 * whether tex gen is needed here and generate it accordingly */
4867 if (!This->texture_name)
4868 {
4869 Assert(!(This->Flags & SFLAG_INTEXTURE));
4870 if (flag & SFLAG_INTEXTURE)
4871 {
4872 struct wined3d_context *context = NULL;
4873 IWineD3DDeviceImpl *device = This->resource.device;
4874 const struct wined3d_gl_info *gl_info;
4875
4876 if (!device->isInDraw) context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
4877 gl_info = context->gl_info;
4878
4879 surface_prepare_texture(This, gl_info, FALSE);
4880
4881 if (context) context_release(context);
4882 }
4883 }
4884
4885 if (!This->texture_name_srgb)
4886 {
4887 Assert(!(This->Flags & SFLAG_INSRGBTEX));
4888 if (flag & SFLAG_INSRGBTEX)
4889 {
4890 struct wined3d_context *context = NULL;
4891 IWineD3DDeviceImpl *device = This->resource.device;
4892 const struct wined3d_gl_info *gl_info;
4893
4894 if (!device->isInDraw) context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
4895 gl_info = context->gl_info;
4896
4897 surface_prepare_texture(This, gl_info, TRUE);
4898
4899 if (context) context_release(context);
4900 }
4901 }
4902 }
4903#endif
4904
4905 This->Flags &= ~SFLAG_LOCATIONS;
4906 This->Flags |= flag;
4907
4908 /* Redraw emulated overlays, if any */
4909 if(flag & SFLAG_INDRAWABLE && !list_empty(&This->overlays)) {
4910 LIST_FOR_EACH_ENTRY(overlay, &This->overlays, IWineD3DSurfaceImpl, overlay_entry) {
4911 IWineD3DSurface_DrawOverlay((IWineD3DSurface *) overlay);
4912 }
4913 }
4914 } else {
4915 if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) && (flag & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX))) {
4916 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&texture) == WINED3D_OK) {
4917 TRACE("Passing to container\n");
4918 IWineD3DBaseTexture_SetDirty(texture, TRUE);
4919 IWineD3DBaseTexture_Release(texture);
4920 }
4921 }
4922
4923 This->Flags &= ~flag;
4924 }
4925
4926#ifdef VBOX_WITH_WDDM
4927 if(VBOXSHRC_IS_SHARED_UNLOCKED(This)) {
4928 /* with the shared resource only texture can be considered valid
4929 * to make sure changes done to the resource in the other device context are visible
4930 * because the resource contents is shared via texture.
4931 * This is why we ensure texture location is the one and only which is always valid */
4932 if(!(This->Flags & SFLAG_INTEXTURE)) {
4933 IWineD3DSurfaceImpl_LoadLocation(iface, SFLAG_INTEXTURE, NULL);
4934 } else {
4935 This->Flags &= ~SFLAG_LOCATIONS;
4936 This->Flags |= SFLAG_INTEXTURE;
4937 }
4938 }
4939 else if (This->Flags & SFLAG_CLIENTMEM)
4940 {
4941 if(!(This->Flags & SFLAG_INSYSMEM)) {
4942 IWineD3DSurfaceImpl_LoadLocation(iface, SFLAG_INSYSMEM, NULL);
4943 } else {
4944 This->Flags &= ~SFLAG_LOCATIONS;
4945 This->Flags |= SFLAG_INSYSMEM;
4946 }
4947
4948 }
4949#endif
4950
4951 if(!(This->Flags & SFLAG_LOCATIONS)) {
4952 ERR("%p: Surface does not have any up to date location\n", This);
4953 }
4954}
4955
4956static inline void surface_blt_to_drawable(IWineD3DSurfaceImpl *This, const RECT *rect_in)
4957{
4958 IWineD3DDeviceImpl *device = This->resource.device;
4959 IWineD3DSwapChainImpl *swapchain;
4960 struct wined3d_context *context;
4961 RECT src_rect, dst_rect;
4962
4963 surface_get_rect(This, rect_in, &src_rect);
4964
4965 context = context_acquire(device, (IWineD3DSurface*)This, CTXUSAGE_BLIT);
4966 if (context->render_offscreen)
4967 {
4968 dst_rect.left = src_rect.left;
4969 dst_rect.right = src_rect.right;
4970 dst_rect.top = src_rect.bottom;
4971 dst_rect.bottom = src_rect.top;
4972 }
4973 else
4974 {
4975 dst_rect = src_rect;
4976 }
4977
4978 device->blitter->set_shader((IWineD3DDevice *) device, This);
4979
4980 ENTER_GL();
4981 draw_textured_quad(This, &src_rect, &dst_rect, WINED3DTEXF_POINT);
4982 LEAVE_GL();
4983
4984 device->blitter->set_shader((IWineD3DDevice *) device, This);
4985
4986 swapchain = (This->Flags & SFLAG_SWAPCHAIN) ? (IWineD3DSwapChainImpl *)This->container : NULL;
4987 if (wined3d_settings.strict_draw_ordering || (swapchain
4988 && ((IWineD3DSurface *)This == swapchain->frontBuffer
4989#ifdef VBOX_WITH_WDDM
4990 || swapchain->device->numContexts > 1
4991#else
4992 || swapchain->num_contexts > 1
4993#endif
4994 )))
4995 wglFlush(); /* Flush to ensure ordering across contexts. */
4996
4997 context_release(context);
4998}
4999
5000/*****************************************************************************
5001 * IWineD3DSurface::LoadLocation
5002 *
5003 * Copies the current surface data from wherever it is to the requested
5004 * location. The location is one of the surface flags, SFLAG_INSYSMEM,
5005 * SFLAG_INTEXTURE and SFLAG_INDRAWABLE. When the surface is current in
5006 * multiple locations, the gl texture is preferred over the drawable, which is
5007 * preferred over system memory. The PBO counts as system memory. If rect is
5008 * not NULL, only the specified rectangle is copied (only supported for
5009 * sysmem<->drawable copies at the moment). If rect is NULL, the destination
5010 * location is marked up to date after the copy.
5011 *
5012 * Parameters:
5013 * flag: Surface location flag to be updated
5014 * rect: rectangle to be copied
5015 *
5016 * Returns:
5017 * WINED3D_OK on success
5018 * WINED3DERR_DEVICELOST on an internal error
5019 *
5020 *****************************************************************************/
5021static HRESULT WINAPI IWineD3DSurfaceImpl_LoadLocation(IWineD3DSurface *iface, DWORD flag, const RECT *rect) {
5022 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
5023 IWineD3DDeviceImpl *device = This->resource.device;
5024 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
5025 struct wined3d_format_desc desc;
5026 CONVERT_TYPES convert;
5027 int width, pitch, outpitch;
5028 BYTE *mem;
5029 BOOL drawable_read_ok = TRUE;
5030 BOOL in_fbo = FALSE;
5031
5032 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5033 if (surface_is_offscreen(iface))
5034 {
5035 /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets.
5036 * Prefer SFLAG_INTEXTURE. */
5037 if (flag == SFLAG_INDRAWABLE) flag = SFLAG_INTEXTURE;
5038 drawable_read_ok = FALSE;
5039 in_fbo = TRUE;
5040 }
5041 else
5042 {
5043 TRACE("Surface %p is an onscreen surface\n", iface);
5044 }
5045 }
5046
5047 TRACE("(%p)->(%s, %p)\n", iface, debug_surflocation(flag), rect);
5048 if(rect) {
5049 TRACE("Rectangle: (%d,%d)-(%d,%d)\n", rect->left, rect->top, rect->right, rect->bottom);
5050 }
5051
5052 if(This->Flags & flag) {
5053 TRACE("Location already up to date\n");
5054#ifdef VBOX_WITH_WDDM
5055 goto post_process;
5056#else
5057 return WINED3D_OK;
5058#endif
5059 }
5060
5061 if(!(This->Flags & SFLAG_LOCATIONS)) {
5062 ERR("%p: Surface does not have any up to date location\n", This);
5063 This->Flags |= SFLAG_LOST;
5064 return WINED3DERR_DEVICELOST;
5065 }
5066
5067 if(flag == SFLAG_INSYSMEM) {
5068 surface_prepare_system_memory(This);
5069
5070 /* Download the surface to system memory */
5071 if (This->Flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX))
5072 {
5073 struct wined3d_context *context = NULL;
5074
5075 if (!device->isInDraw) context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
5076
5077 surface_bind_and_dirtify(This, !(This->Flags & SFLAG_INTEXTURE));
5078 surface_download_data(This, gl_info);
5079
5080 if (context) context_release(context);
5081 }
5082 else
5083 {
5084 /* Note: It might be faster to download into a texture first. */
5085 read_from_framebuffer(This, rect,
5086 This->resource.allocatedMemory,
5087 IWineD3DSurface_GetPitch(iface));
5088 }
5089 } else if(flag == SFLAG_INDRAWABLE) {
5090 if(This->Flags & SFLAG_INTEXTURE) {
5091 surface_blt_to_drawable(This, rect);
5092 } else {
5093 int byte_count;
5094 if((This->Flags & SFLAG_LOCATIONS) == SFLAG_INSRGBTEX) {
5095 /* This needs a shader to convert the srgb data sampled from the GL texture into RGB
5096 * values, otherwise we get incorrect values in the target. For now go the slow way
5097 * via a system memory copy
5098 */
5099 IWineD3DSurfaceImpl_LoadLocation(iface, SFLAG_INSYSMEM, rect);
5100 }
5101
5102 d3dfmt_get_conv(This, FALSE /* We need color keying */, FALSE /* We won't use textures */, &desc, &convert);
5103
5104 /* The width is in 'length' not in bytes */
5105 width = This->currentDesc.Width;
5106 pitch = IWineD3DSurface_GetPitch(iface);
5107
5108 /* Don't use PBOs for converted surfaces. During PBO conversion we look at SFLAG_CONVERTED
5109 * but it isn't set (yet) in all cases it is getting called. */
5110 if ((convert != NO_CONVERSION) && (This->Flags & SFLAG_PBO))
5111 {
5112 struct wined3d_context *context = NULL;
5113
5114 TRACE("Removing the pbo attached to surface %p\n", This);
5115
5116 if (!device->isInDraw) context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
5117 surface_remove_pbo(This, gl_info);
5118 if (context) context_release(context);
5119 }
5120
5121 if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
5122 int height = This->currentDesc.Height;
5123 byte_count = desc.conv_byte_count;
5124
5125 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
5126 outpitch = width * byte_count;
5127 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
5128
5129 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
5130 if(!mem) {
5131 ERR("Out of memory %d, %d!\n", outpitch, height);
5132 return WINED3DERR_OUTOFVIDEOMEMORY;
5133 }
5134 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
5135
5136 This->Flags |= SFLAG_CONVERTED;
5137 } else {
5138 This->Flags &= ~SFLAG_CONVERTED;
5139 mem = This->resource.allocatedMemory;
5140 byte_count = desc.byte_count;
5141 }
5142
5143 flush_to_framebuffer_drawpixels(This, desc.glFormat, desc.glType, byte_count, mem);
5144
5145 /* Don't delete PBO memory */
5146 if((mem != This->resource.allocatedMemory) && !(This->Flags & SFLAG_PBO))
5147 HeapFree(GetProcessHeap(), 0, mem);
5148 }
5149 } else /* if(flag & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) */ {
5150 if (drawable_read_ok && (This->Flags & SFLAG_INDRAWABLE)) {
5151 read_from_framebuffer_texture(This, flag == SFLAG_INSRGBTEX);
5152 }
5153 else
5154 {
5155 /* Upload from system memory */
5156 BOOL srgb = flag == SFLAG_INSRGBTEX;
5157 struct wined3d_context *context = NULL;
5158
5159 d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */,
5160 &desc, &convert);
5161
5162 if(srgb) {
5163 if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INSYSMEM)) == SFLAG_INTEXTURE) {
5164 /* Performance warning ... */
5165 FIXME("%p: Downloading rgb texture to reload it as srgb\n", This);
5166 IWineD3DSurfaceImpl_LoadLocation(iface, SFLAG_INSYSMEM, rect);
5167 }
5168 } else {
5169 if((This->Flags & (SFLAG_INSRGBTEX | SFLAG_INSYSMEM)) == SFLAG_INSRGBTEX) {
5170 /* Performance warning ... */
5171 FIXME("%p: Downloading srgb texture to reload it as rgb\n", This);
5172 IWineD3DSurfaceImpl_LoadLocation(iface, SFLAG_INSYSMEM, rect);
5173 }
5174 }
5175 if(!(This->Flags & SFLAG_INSYSMEM)) {
5176 /* Should not happen */
5177 ERR("Trying to load a texture from sysmem, but SFLAG_INSYSMEM is not set\n");
5178 /* Lets hope we get it from somewhere... */
5179 IWineD3DSurfaceImpl_LoadLocation(iface, SFLAG_INSYSMEM, rect);
5180 }
5181
5182 if (!device->isInDraw) context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
5183
5184 surface_prepare_texture(This, gl_info, srgb);
5185 surface_bind_and_dirtify(This, srgb);
5186
5187 if(This->CKeyFlags & WINEDDSD_CKSRCBLT) {
5188 This->Flags |= SFLAG_GLCKEY;
5189 This->glCKey = This->SrcBltCKey;
5190 }
5191 else This->Flags &= ~SFLAG_GLCKEY;
5192
5193 /* The width is in 'length' not in bytes */
5194 width = This->currentDesc.Width;
5195 pitch = IWineD3DSurface_GetPitch(iface);
5196
5197 /* Don't use PBOs for converted surfaces. During PBO conversion we look at SFLAG_CONVERTED
5198 * but it isn't set (yet) in all cases it is getting called. */
5199 if((convert != NO_CONVERSION) && (This->Flags & SFLAG_PBO)) {
5200 TRACE("Removing the pbo attached to surface %p\n", This);
5201 surface_remove_pbo(This, gl_info);
5202 }
5203
5204 if(desc.convert) {
5205 /* This code is entered for texture formats which need a fixup. */
5206 int height = This->currentDesc.Height;
5207
5208 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
5209 outpitch = width * desc.conv_byte_count;
5210 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
5211
5212 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
5213 if(!mem) {
5214 ERR("Out of memory %d, %d!\n", outpitch, height);
5215 if (context) context_release(context);
5216 return WINED3DERR_OUTOFVIDEOMEMORY;
5217 }
5218 desc.convert(This->resource.allocatedMemory, mem, pitch, width, height);
5219 } else if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
5220 /* This code is only entered for color keying fixups */
5221 int height = This->currentDesc.Height;
5222
5223 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
5224 outpitch = width * desc.conv_byte_count;
5225 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
5226
5227 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
5228 if(!mem) {
5229 ERR("Out of memory %d, %d!\n", outpitch, height);
5230 if (context) context_release(context);
5231 return WINED3DERR_OUTOFVIDEOMEMORY;
5232 }
5233 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
5234 } else {
5235 mem = This->resource.allocatedMemory;
5236 }
5237
5238 /* Make sure the correct pitch is used */
5239 ENTER_GL();
5240 glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
5241 LEAVE_GL();
5242
5243 if (mem || (This->Flags & SFLAG_PBO))
5244 surface_upload_data(This, gl_info, &desc, srgb, mem);
5245
5246 /* Restore the default pitch */
5247 ENTER_GL();
5248 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5249 LEAVE_GL();
5250
5251 if (context) context_release(context);
5252
5253 /* Don't delete PBO memory */
5254 if((mem != This->resource.allocatedMemory) && !(This->Flags & SFLAG_PBO))
5255 HeapFree(GetProcessHeap(), 0, mem);
5256 }
5257 }
5258
5259#ifdef VBOX_WITH_WDDM
5260post_process:
5261
5262 if (VBOXSHRC_IS_SHARED_UNLOCKED(This))
5263 {
5264 /* with the shared resource only texture can be considered valid
5265 * to make sure changes done to the resource in the other device context are visible
5266 * because the resource contents is shared via texture.
5267 * One can load and use other locations as needed,
5268 * but they should be reloaded each time on each usage */
5269 Assert(!!(This->Flags & SFLAG_INTEXTURE) || !!(flag & SFLAG_INTEXTURE));
5270 This->Flags &= ~SFLAG_LOCATIONS;
5271 This->Flags |= SFLAG_INTEXTURE;
5272 /* @todo: SFLAG_INSRGBTEX ?? */
5273// if (in_fbo)
5274// {
5275// This->Flags |= SFLAG_INDRAWABLE;
5276// }
5277 }
5278 else if (This->Flags & SFLAG_CLIENTMEM)
5279 {
5280 Assert(!!(This->Flags & SFLAG_INSYSMEM));
5281 This->Flags &= ~SFLAG_LOCATIONS;
5282 This->Flags |= SFLAG_INSYSMEM;
5283 }
5284 else
5285#endif
5286 {
5287 if(rect == NULL) {
5288 This->Flags |= flag;
5289 }
5290
5291 if (in_fbo && (This->Flags & (SFLAG_INTEXTURE | SFLAG_INDRAWABLE))) {
5292 /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets. */
5293 This->Flags |= (SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
5294 }
5295 }
5296
5297 return WINED3D_OK;
5298}
5299
5300static HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container)
5301{
5302 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
5303 IWineD3DSwapChain *swapchain = NULL;
5304
5305 /* Update the drawable size method */
5306 if(container) {
5307 IWineD3DBase_QueryInterface(container, &IID_IWineD3DSwapChain, (void **) &swapchain);
5308 }
5309 if(swapchain) {
5310 This->get_drawable_size = get_drawable_size_swapchain;
5311 IWineD3DSwapChain_Release(swapchain);
5312 } else if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5313 switch(wined3d_settings.offscreen_rendering_mode) {
5314 case ORM_FBO: This->get_drawable_size = get_drawable_size_fbo; break;
5315 case ORM_BACKBUFFER: This->get_drawable_size = get_drawable_size_backbuffer; break;
5316 }
5317 }
5318
5319 return IWineD3DBaseSurfaceImpl_SetContainer(iface, container);
5320}
5321
5322static WINED3DSURFTYPE WINAPI IWineD3DSurfaceImpl_GetImplType(IWineD3DSurface *iface) {
5323 return SURFACE_OPENGL;
5324}
5325
5326static HRESULT WINAPI IWineD3DSurfaceImpl_DrawOverlay(IWineD3DSurface *iface) {
5327 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
5328 HRESULT hr;
5329
5330 /* If there's no destination surface there is nothing to do */
5331 if(!This->overlay_dest) return WINED3D_OK;
5332
5333 /* Blt calls ModifyLocation on the dest surface, which in turn calls DrawOverlay to
5334 * update the overlay. Prevent an endless recursion
5335 */
5336 if(This->overlay_dest->Flags & SFLAG_INOVERLAYDRAW) {
5337 return WINED3D_OK;
5338 }
5339 This->overlay_dest->Flags |= SFLAG_INOVERLAYDRAW;
5340 hr = IWineD3DSurfaceImpl_Blt((IWineD3DSurface *) This->overlay_dest, &This->overlay_destrect,
5341 iface, &This->overlay_srcrect, WINEDDBLT_WAIT,
5342 NULL, WINED3DTEXF_LINEAR);
5343 This->overlay_dest->Flags &= ~SFLAG_INOVERLAYDRAW;
5344
5345 return hr;
5346}
5347
5348BOOL surface_is_offscreen(IWineD3DSurface *iface)
5349{
5350 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
5351 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) This->container;
5352
5353 /* Not on a swapchain - must be offscreen */
5354 if (!(This->Flags & SFLAG_SWAPCHAIN)) return TRUE;
5355
5356 /* The front buffer is always onscreen */
5357 if(iface == swapchain->frontBuffer) return FALSE;
5358
5359 /* If the swapchain is rendered to an FBO, the backbuffer is
5360 * offscreen, otherwise onscreen */
5361 return swapchain->render_to_fbo;
5362}
5363
5364#ifdef VBOX_WITH_WDDM
5365static HRESULT WINAPI IWineD3DSurfaceImpl_SetShRcState(IWineD3DSurface *iface, VBOXWINEEX_SHRC_STATE enmState) {
5366 HRESULT hr;
5367
5368 hr = IWineD3DResourceImpl_SetShRcState((IWineD3DResource*)iface, enmState);
5369 if (FAILED(hr))
5370 {
5371 ERR("IWineD3DResource_SetShRcState failed");
5372 return hr;
5373 }
5374
5375 return WINED3D_OK;
5376}
5377#endif
5378
5379const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
5380{
5381 /* IUnknown */
5382 IWineD3DBaseSurfaceImpl_QueryInterface,
5383 IWineD3DBaseSurfaceImpl_AddRef,
5384 IWineD3DSurfaceImpl_Release,
5385 /* IWineD3DResource */
5386 IWineD3DBaseSurfaceImpl_GetParent,
5387 IWineD3DBaseSurfaceImpl_SetPrivateData,
5388 IWineD3DBaseSurfaceImpl_GetPrivateData,
5389 IWineD3DBaseSurfaceImpl_FreePrivateData,
5390 IWineD3DBaseSurfaceImpl_SetPriority,
5391 IWineD3DBaseSurfaceImpl_GetPriority,
5392 IWineD3DSurfaceImpl_PreLoad,
5393 IWineD3DSurfaceImpl_UnLoad,
5394 IWineD3DBaseSurfaceImpl_GetType,
5395#ifdef VBOX_WITH_WDDM
5396 IWineD3DSurfaceImpl_SetShRcState,
5397#endif
5398 /* IWineD3DSurface */
5399 IWineD3DBaseSurfaceImpl_GetContainer,
5400 IWineD3DBaseSurfaceImpl_GetDesc,
5401 IWineD3DSurfaceImpl_LockRect,
5402 IWineD3DSurfaceImpl_UnlockRect,
5403 IWineD3DSurfaceImpl_GetDC,
5404 IWineD3DSurfaceImpl_ReleaseDC,
5405 IWineD3DSurfaceImpl_Flip,
5406 IWineD3DSurfaceImpl_Blt,
5407 IWineD3DBaseSurfaceImpl_GetBltStatus,
5408 IWineD3DBaseSurfaceImpl_GetFlipStatus,
5409 IWineD3DBaseSurfaceImpl_IsLost,
5410 IWineD3DBaseSurfaceImpl_Restore,
5411 IWineD3DSurfaceImpl_BltFast,
5412 IWineD3DBaseSurfaceImpl_GetPalette,
5413 IWineD3DBaseSurfaceImpl_SetPalette,
5414 IWineD3DSurfaceImpl_RealizePalette,
5415 IWineD3DBaseSurfaceImpl_SetColorKey,
5416 IWineD3DBaseSurfaceImpl_GetPitch,
5417 IWineD3DSurfaceImpl_SetMem,
5418 IWineD3DBaseSurfaceImpl_SetOverlayPosition,
5419 IWineD3DBaseSurfaceImpl_GetOverlayPosition,
5420 IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder,
5421 IWineD3DBaseSurfaceImpl_UpdateOverlay,
5422 IWineD3DBaseSurfaceImpl_SetClipper,
5423 IWineD3DBaseSurfaceImpl_GetClipper,
5424 /* Internal use: */
5425 IWineD3DSurfaceImpl_LoadTexture,
5426 IWineD3DSurfaceImpl_BindTexture,
5427 IWineD3DSurfaceImpl_SaveSnapshot,
5428 IWineD3DSurfaceImpl_SetContainer,
5429 IWineD3DBaseSurfaceImpl_GetData,
5430 IWineD3DSurfaceImpl_SetFormat,
5431 IWineD3DSurfaceImpl_PrivateSetup,
5432 IWineD3DSurfaceImpl_ModifyLocation,
5433 IWineD3DSurfaceImpl_LoadLocation,
5434 IWineD3DSurfaceImpl_GetImplType,
5435 IWineD3DSurfaceImpl_DrawOverlay
5436};
5437
5438static HRESULT ffp_blit_alloc(IWineD3DDevice *iface) { return WINED3D_OK; }
5439/* Context activation is done by the caller. */
5440static void ffp_blit_free(IWineD3DDevice *iface) { }
5441
5442/* This function is used in case of 8bit paletted textures using GL_EXT_paletted_texture */
5443/* Context activation is done by the caller. */
5444static void ffp_blit_p8_upload_palette(IWineD3DSurfaceImpl *surface, const struct wined3d_gl_info *gl_info)
5445{
5446 BYTE table[256][4];
5447 BOOL colorkey_active = (surface->CKeyFlags & WINEDDSD_CKSRCBLT) ? TRUE : FALSE;
5448
5449 d3dfmt_p8_init_palette(surface, table, colorkey_active);
5450
5451 TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n");
5452 ENTER_GL();
5453 GL_EXTCALL(glColorTableEXT(surface->texture_target, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, table));
5454 LEAVE_GL();
5455}
5456
5457/* Context activation is done by the caller. */
5458static HRESULT ffp_blit_set(IWineD3DDevice *iface, IWineD3DSurfaceImpl *surface)
5459{
5460 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) iface;
5461 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
5462 enum complex_fixup fixup = get_complex_fixup(surface->resource.format_desc->color_fixup);
5463
5464 /* When EXT_PALETTED_TEXTURE is around, palette conversion is done by the GPU
5465 * else the surface is converted in software at upload time in LoadLocation.
5466 */
5467 if(fixup == COMPLEX_FIXUP_P8 && gl_info->supported[EXT_PALETTED_TEXTURE])
5468 ffp_blit_p8_upload_palette(surface, gl_info);
5469
5470 ENTER_GL();
5471 glEnable(surface->texture_target);
5472 checkGLcall("glEnable(surface->texture_target)");
5473 LEAVE_GL();
5474 return WINED3D_OK;
5475}
5476
5477/* Context activation is done by the caller. */
5478static void ffp_blit_unset(IWineD3DDevice *iface)
5479{
5480 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) iface;
5481 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
5482
5483 ENTER_GL();
5484 glDisable(GL_TEXTURE_2D);
5485 checkGLcall("glDisable(GL_TEXTURE_2D)");
5486 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
5487 {
5488 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
5489 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
5490 }
5491 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
5492 {
5493 glDisable(GL_TEXTURE_RECTANGLE_ARB);
5494 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
5495 }
5496 LEAVE_GL();
5497}
5498
5499static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info, enum blit_operation blit_op,
5500 const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool,
5501 const struct wined3d_format_desc *src_format_desc,
5502 const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool,
5503 const struct wined3d_format_desc *dst_format_desc)
5504{
5505 enum complex_fixup src_fixup;
5506
5507 if (blit_op == BLIT_OP_COLOR_FILL)
5508 {
5509 if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
5510 {
5511 TRACE("Color fill not supported\n");
5512 return FALSE;
5513 }
5514
5515 return TRUE;
5516 }
5517
5518 src_fixup = get_complex_fixup(src_format_desc->color_fixup);
5519 if (TRACE_ON(d3d_surface) && TRACE_ON(d3d))
5520 {
5521 TRACE("Checking support for fixup:\n");
5522 dump_color_fixup_desc(src_format_desc->color_fixup);
5523 }
5524
5525 if (blit_op != BLIT_OP_BLIT)
5526 {
5527 TRACE("Unsupported blit_op=%d\n", blit_op);
5528 return FALSE;
5529 }
5530
5531 if (!is_identity_fixup(dst_format_desc->color_fixup))
5532 {
5533 TRACE("Destination fixups are not supported\n");
5534 return FALSE;
5535 }
5536
5537 if (src_fixup == COMPLEX_FIXUP_P8 && gl_info->supported[EXT_PALETTED_TEXTURE])
5538 {
5539 TRACE("P8 fixup supported\n");
5540 return TRUE;
5541 }
5542
5543 /* We only support identity conversions. */
5544 if (is_identity_fixup(src_format_desc->color_fixup))
5545 {
5546 TRACE("[OK]\n");
5547 return TRUE;
5548 }
5549
5550 TRACE("[FAILED]\n");
5551 return FALSE;
5552}
5553
5554static HRESULT ffp_blit_color_fill(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect, DWORD fill_color)
5555{
5556 return IWineD3DDeviceImpl_ClearSurface(device, dst_surface, 1 /* Number of rectangles */,
5557 (const WINED3DRECT*)dst_rect, WINED3DCLEAR_TARGET, fill_color, 0.0f /* Z */, 0 /* Stencil */);
5558}
5559
5560const struct blit_shader ffp_blit = {
5561 ffp_blit_alloc,
5562 ffp_blit_free,
5563 ffp_blit_set,
5564 ffp_blit_unset,
5565 ffp_blit_supported,
5566 ffp_blit_color_fill
5567};
5568
5569static HRESULT cpu_blit_alloc(IWineD3DDevice *iface)
5570{
5571 return WINED3D_OK;
5572}
5573
5574/* Context activation is done by the caller. */
5575static void cpu_blit_free(IWineD3DDevice *iface)
5576{
5577}
5578
5579/* Context activation is done by the caller. */
5580static HRESULT cpu_blit_set(IWineD3DDevice *iface, IWineD3DSurfaceImpl *surface)
5581{
5582 return WINED3D_OK;
5583}
5584
5585/* Context activation is done by the caller. */
5586static void cpu_blit_unset(IWineD3DDevice *iface)
5587{
5588}
5589
5590static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info, enum blit_operation blit_op,
5591 const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool,
5592 const struct wined3d_format_desc *src_format_desc,
5593 const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool,
5594 const struct wined3d_format_desc *dst_format_desc)
5595{
5596 if (blit_op == BLIT_OP_COLOR_FILL)
5597 {
5598 return TRUE;
5599 }
5600
5601 return FALSE;
5602}
5603
5604static HRESULT cpu_blit_color_fill(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect, DWORD fill_color)
5605{
5606 WINEDDBLTFX BltFx;
5607 memset(&BltFx, 0, sizeof(BltFx));
5608 BltFx.dwSize = sizeof(BltFx);
5609 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(fill_color, dst_surface->resource.format_desc->format);
5610 return IWineD3DBaseSurfaceImpl_Blt((IWineD3DSurface*)dst_surface, dst_rect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5611}
5612
5613const struct blit_shader cpu_blit = {
5614 cpu_blit_alloc,
5615 cpu_blit_free,
5616 cpu_blit_set,
5617 cpu_blit_unset,
5618 cpu_blit_supported,
5619 cpu_blit_color_fill
5620};
5621
5622static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum blit_operation blit_op,
5623 const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool,
5624 const struct wined3d_format_desc *src_format_desc,
5625 const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool,
5626 const struct wined3d_format_desc *dst_format_desc)
5627{
5628 if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
5629 return FALSE;
5630
5631 /* We only support blitting. Things like color keying / color fill should
5632 * be handled by other blitters.
5633 */
5634 if (blit_op != BLIT_OP_BLIT)
5635 return FALSE;
5636
5637 /* Source and/or destination need to be on the GL side */
5638 if (src_pool == WINED3DPOOL_SYSTEMMEM || dst_pool == WINED3DPOOL_SYSTEMMEM)
5639 return FALSE;
5640
5641 if(!((src_format_desc->Flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (src_usage & WINED3DUSAGE_RENDERTARGET))
5642 && ((dst_format_desc->Flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
5643 return FALSE;
5644
5645 if (!is_identity_fixup(src_format_desc->color_fixup) ||
5646 !is_identity_fixup(dst_format_desc->color_fixup))
5647 return FALSE;
5648
5649 if (!(src_format_desc->format == dst_format_desc->format
5650 || (is_identity_fixup(src_format_desc->color_fixup)
5651 && is_identity_fixup(dst_format_desc->color_fixup))))
5652 return FALSE;
5653
5654 return TRUE;
5655}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette