VirtualBox

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

Last change on this file since 39570 was 39150, checked in by vboxsync, 13 years ago

wddm: avoid unnecessary window creation (caused img flickering for MacOS guest), etc.

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