VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Wine_new/wined3d/surface.c@ 48345

Last change on this file since 48345 was 48345, checked in by vboxsync, 11 years ago

header fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 277.9 KB
Line 
1/*
2 * Copyright 1997-2000 Marcus Meissner
3 * Copyright 1998-2000 Lionel Ulmer
4 * Copyright 2000-2001 TransGaming Technologies Inc.
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2002-2003 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2011 Stefan Dösinger for CodeWeavers
10 * Copyright 2007-2008 Henri Verbeet
11 * Copyright 2006-2008 Roderick Colenbrander
12 * Copyright 2009-2011 Henri Verbeet for CodeWeavers
13 *
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
18 *
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 */
28
29/*
30 * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
31 * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
32 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
33 * a choice of LGPL license versions is made available with the language indicating
34 * that LGPLv2 or any later version may be used, or where a choice of which version
35 * of the LGPL is applied is otherwise unspecified.
36 */
37
38#include "config.h"
39#include "wine/port.h"
40#include "wined3d_private.h"
41#ifdef VBOX_WITH_WINE_FIXES
42# include <float.h>
43#endif
44
45WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
46WINE_DECLARE_DEBUG_CHANNEL(d3d_perf);
47WINE_DECLARE_DEBUG_CHANNEL(d3d);
48
49#ifdef VBOX_WITH_WDDM
50void surface_shrc_lock_surf(struct wined3d_surface *surf)
51{
52 VBOXSHRC_LOCK(surf);
53}
54
55void surface_shrc_unlock_surf(struct wined3d_surface *surf)
56{
57 VBOXSHRC_UNLOCK(surf);
58 if (VBOXSHRC_IS_LOCKED(surf))
59 return;
60
61 /* perform data->texture synchronization */
62 surface_load_location(surf, SFLAG_INTEXTURE, NULL);
63}
64
65void surface_shrc_lock(struct wined3d_surface *surf)
66{
67 if (!VBOXSHRC_IS_SHARED(surf))
68 return;
69
70 surface_shrc_lock_surf(surf);
71}
72
73void surface_shrc_unlock(struct wined3d_surface *surf)
74{
75 if (!VBOXSHRC_IS_SHARED(surf))
76 return;
77 surface_shrc_unlock_surf(surf);
78}
79#endif
80
81static HRESULT surface_cpu_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
82 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
83 const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter);
84static HRESULT IWineD3DSurfaceImpl_BltOverride(struct wined3d_surface *dst_surface, const RECT *dst_rect,
85 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags, const WINEDDBLTFX *fx,
86 enum wined3d_texture_filter_type filter);
87
88static void surface_cleanup(struct wined3d_surface *surface)
89{
90 struct wined3d_surface *overlay, *cur;
91
92 TRACE("surface %p.\n", surface);
93
94 if (surface->texture_name || (surface->flags & SFLAG_PBO)
95 || surface->rb_multisample || surface->rb_resolved
96 || !list_empty(&surface->renderbuffers))
97 {
98 struct wined3d_renderbuffer_entry *entry, *entry2;
99 const struct wined3d_gl_info *gl_info;
100 struct wined3d_context *context;
101
102 context = context_acquire(surface->resource.device, NULL);
103 gl_info = context->gl_info;
104
105 if (surface->texture_name)
106 {
107 TRACE("Deleting texture %u.\n", surface->texture_name);
108#ifdef VBOX_WITH_WDDM
109 texture_gl_delete(surface->texture_name);
110#else
111 gl_info->gl_ops.gl.p_glDeleteTextures(1, &surface->texture_name);
112#endif
113 }
114
115 if (surface->flags & SFLAG_PBO)
116 {
117 TRACE("Deleting PBO %u.\n", surface->pbo);
118 GL_EXTCALL(glDeleteBuffersARB(1, &surface->pbo));
119 }
120
121 if (surface->rb_multisample)
122 {
123 TRACE("Deleting multisample renderbuffer %u.\n", surface->rb_multisample);
124 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_multisample);
125 }
126
127 if (surface->rb_resolved)
128 {
129 TRACE("Deleting resolved renderbuffer %u.\n", surface->rb_resolved);
130 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_resolved);
131 }
132
133 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
134 {
135 TRACE("Deleting renderbuffer %u.\n", entry->id);
136 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
137 HeapFree(GetProcessHeap(), 0, entry);
138 }
139
140 context_release(context);
141 }
142
143 if (surface->flags & SFLAG_DIBSECTION)
144 {
145 DeleteDC(surface->hDC);
146 DeleteObject(surface->dib.DIBsection);
147 surface->dib.bitmap_data = NULL;
148 surface->resource.allocatedMemory = NULL;
149 }
150
151 if (surface->flags & SFLAG_USERPTR)
152 wined3d_surface_set_mem(surface, NULL, 0);
153 if (surface->overlay_dest)
154 list_remove(&surface->overlay_entry);
155
156 LIST_FOR_EACH_ENTRY_SAFE(overlay, cur, &surface->overlays, struct wined3d_surface, overlay_entry)
157 {
158 list_remove(&overlay->overlay_entry);
159 overlay->overlay_dest = NULL;
160 }
161
162 resource_cleanup(&surface->resource);
163
164#ifdef VBOX_WITH_WDDM
165 /* @rodo: CHECK AND REMOVE : this should not be necessary anymore */
166 {
167 struct wined3d_device *device = surface->resource.device;
168 struct wined3d_context *context;
169 UINT i;
170 for (i = 0; i < device->context_count; ++i)
171 {
172 context = device->contexts[i];
173 /* pretty hacky, @todo: check if the context is acquired and re-acquire it with the new swapchain */
174 if (context->current_rt == surface)
175 {
176 Assert(0);
177 }
178 }
179 }
180#endif
181
182}
183
184void surface_update_draw_binding(struct wined3d_surface *surface)
185{
186 if (!surface_is_offscreen(surface) || wined3d_settings.offscreen_rendering_mode != ORM_FBO)
187 surface->draw_binding = SFLAG_INDRAWABLE;
188 else if (surface->resource.multisample_type)
189 surface->draw_binding = SFLAG_INRB_MULTISAMPLE;
190 else
191 surface->draw_binding = SFLAG_INTEXTURE;
192}
193
194void surface_set_swapchain(struct wined3d_surface *surface, struct wined3d_swapchain *swapchain)
195{
196 TRACE("surface %p, swapchain %p.\n", surface, swapchain);
197
198 if (swapchain)
199 {
200 surface->get_drawable_size = get_drawable_size_swapchain;
201 }
202 else
203 {
204 switch (wined3d_settings.offscreen_rendering_mode)
205 {
206 case ORM_FBO:
207 surface->get_drawable_size = get_drawable_size_fbo;
208 break;
209
210 case ORM_BACKBUFFER:
211 surface->get_drawable_size = get_drawable_size_backbuffer;
212 break;
213
214 default:
215 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode);
216 return;
217 }
218 }
219
220 surface->swapchain = swapchain;
221 surface_update_draw_binding(surface);
222}
223
224void surface_set_container(struct wined3d_surface *surface, struct wined3d_texture *container)
225{
226 TRACE("surface %p, container %p.\n", surface, container);
227
228 if (!surface->swapchain)
229 {
230 switch (wined3d_settings.offscreen_rendering_mode)
231 {
232 case ORM_FBO:
233 surface->get_drawable_size = get_drawable_size_fbo;
234 break;
235
236 case ORM_BACKBUFFER:
237 surface->get_drawable_size = get_drawable_size_backbuffer;
238 break;
239
240 default:
241 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode);
242 return;
243 }
244 }
245
246 surface->container = container;
247 surface_update_draw_binding(surface);
248}
249
250struct blt_info
251{
252 GLenum binding;
253 GLenum bind_target;
254 enum tex_types tex_type;
255 GLfloat coords[4][3];
256};
257
258struct float_rect
259{
260 float l;
261 float t;
262 float r;
263 float b;
264};
265
266static inline void cube_coords_float(const RECT *r, UINT w, UINT h, struct float_rect *f)
267{
268 f->l = ((r->left * 2.0f) / w) - 1.0f;
269 f->t = ((r->top * 2.0f) / h) - 1.0f;
270 f->r = ((r->right * 2.0f) / w) - 1.0f;
271 f->b = ((r->bottom * 2.0f) / h) - 1.0f;
272}
273
274static void surface_get_blt_info(GLenum target, const RECT *rect, GLsizei w, GLsizei h, struct blt_info *info)
275{
276 GLfloat (*coords)[3] = info->coords;
277 struct float_rect f;
278
279 switch (target)
280 {
281 default:
282 FIXME("Unsupported texture target %#x\n", target);
283 /* Fall back to GL_TEXTURE_2D */
284 case GL_TEXTURE_2D:
285 info->binding = GL_TEXTURE_BINDING_2D;
286 info->bind_target = GL_TEXTURE_2D;
287 info->tex_type = tex_2d;
288 coords[0][0] = (float)rect->left / w;
289 coords[0][1] = (float)rect->top / h;
290 coords[0][2] = 0.0f;
291
292 coords[1][0] = (float)rect->right / w;
293 coords[1][1] = (float)rect->top / h;
294 coords[1][2] = 0.0f;
295
296 coords[2][0] = (float)rect->left / w;
297 coords[2][1] = (float)rect->bottom / h;
298 coords[2][2] = 0.0f;
299
300 coords[3][0] = (float)rect->right / w;
301 coords[3][1] = (float)rect->bottom / h;
302 coords[3][2] = 0.0f;
303 break;
304
305 case GL_TEXTURE_RECTANGLE_ARB:
306 info->binding = GL_TEXTURE_BINDING_RECTANGLE_ARB;
307 info->bind_target = GL_TEXTURE_RECTANGLE_ARB;
308 info->tex_type = tex_rect;
309 coords[0][0] = rect->left; coords[0][1] = rect->top; coords[0][2] = 0.0f;
310 coords[1][0] = rect->right; coords[1][1] = rect->top; coords[1][2] = 0.0f;
311 coords[2][0] = rect->left; coords[2][1] = rect->bottom; coords[2][2] = 0.0f;
312 coords[3][0] = rect->right; coords[3][1] = rect->bottom; coords[3][2] = 0.0f;
313 break;
314
315 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
316 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
317 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
318 info->tex_type = tex_cube;
319 cube_coords_float(rect, w, h, &f);
320
321 coords[0][0] = 1.0f; coords[0][1] = -f.t; coords[0][2] = -f.l;
322 coords[1][0] = 1.0f; coords[1][1] = -f.t; coords[1][2] = -f.r;
323 coords[2][0] = 1.0f; coords[2][1] = -f.b; coords[2][2] = -f.l;
324 coords[3][0] = 1.0f; coords[3][1] = -f.b; coords[3][2] = -f.r;
325 break;
326
327 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
328 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
329 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
330 info->tex_type = tex_cube;
331 cube_coords_float(rect, w, h, &f);
332
333 coords[0][0] = -1.0f; coords[0][1] = -f.t; coords[0][2] = f.l;
334 coords[1][0] = -1.0f; coords[1][1] = -f.t; coords[1][2] = f.r;
335 coords[2][0] = -1.0f; coords[2][1] = -f.b; coords[2][2] = f.l;
336 coords[3][0] = -1.0f; coords[3][1] = -f.b; coords[3][2] = f.r;
337 break;
338
339 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
340 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
341 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
342 info->tex_type = tex_cube;
343 cube_coords_float(rect, w, h, &f);
344
345 coords[0][0] = f.l; coords[0][1] = 1.0f; coords[0][2] = f.t;
346 coords[1][0] = f.r; coords[1][1] = 1.0f; coords[1][2] = f.t;
347 coords[2][0] = f.l; coords[2][1] = 1.0f; coords[2][2] = f.b;
348 coords[3][0] = f.r; coords[3][1] = 1.0f; coords[3][2] = f.b;
349 break;
350
351 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
352 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
353 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
354 info->tex_type = tex_cube;
355 cube_coords_float(rect, w, h, &f);
356
357 coords[0][0] = f.l; coords[0][1] = -1.0f; coords[0][2] = -f.t;
358 coords[1][0] = f.r; coords[1][1] = -1.0f; coords[1][2] = -f.t;
359 coords[2][0] = f.l; coords[2][1] = -1.0f; coords[2][2] = -f.b;
360 coords[3][0] = f.r; coords[3][1] = -1.0f; coords[3][2] = -f.b;
361 break;
362
363 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
364 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
365 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
366 info->tex_type = tex_cube;
367 cube_coords_float(rect, w, h, &f);
368
369 coords[0][0] = f.l; coords[0][1] = -f.t; coords[0][2] = 1.0f;
370 coords[1][0] = f.r; coords[1][1] = -f.t; coords[1][2] = 1.0f;
371 coords[2][0] = f.l; coords[2][1] = -f.b; coords[2][2] = 1.0f;
372 coords[3][0] = f.r; coords[3][1] = -f.b; coords[3][2] = 1.0f;
373 break;
374
375 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
376 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
377 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
378 info->tex_type = tex_cube;
379 cube_coords_float(rect, w, h, &f);
380
381 coords[0][0] = -f.l; coords[0][1] = -f.t; coords[0][2] = -1.0f;
382 coords[1][0] = -f.r; coords[1][1] = -f.t; coords[1][2] = -1.0f;
383 coords[2][0] = -f.l; coords[2][1] = -f.b; coords[2][2] = -1.0f;
384 coords[3][0] = -f.r; coords[3][1] = -f.b; coords[3][2] = -1.0f;
385 break;
386 }
387}
388
389static void surface_get_rect(const struct wined3d_surface *surface, const RECT *rect_in, RECT *rect_out)
390{
391 if (rect_in)
392 *rect_out = *rect_in;
393 else
394 {
395 rect_out->left = 0;
396 rect_out->top = 0;
397 rect_out->right = surface->resource.width;
398 rect_out->bottom = surface->resource.height;
399 }
400}
401
402/* Context activation is done by the caller. */
403void draw_textured_quad(const struct wined3d_surface *src_surface, struct wined3d_context *context,
404 const RECT *src_rect, const RECT *dst_rect, enum wined3d_texture_filter_type filter)
405{
406 const struct wined3d_gl_info *gl_info = context->gl_info;
407 struct blt_info info;
408
409 surface_get_blt_info(src_surface->texture_target, src_rect, src_surface->pow2Width, src_surface->pow2Height, &info);
410
411 gl_info->gl_ops.gl.p_glEnable(info.bind_target);
412 checkGLcall("glEnable(bind_target)");
413
414 context_bind_texture(context, info.bind_target, src_surface->texture_name);
415
416 /* Filtering for StretchRect */
417 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_MAG_FILTER,
418 wined3d_gl_mag_filter(magLookup, filter));
419 checkGLcall("glTexParameteri");
420 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_MIN_FILTER,
421 wined3d_gl_min_mip_filter(minMipLookup, filter, WINED3D_TEXF_NONE));
422 checkGLcall("glTexParameteri");
423 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
424 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
425 if (context->gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
426 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
427 gl_info->gl_ops.gl.p_glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
428 checkGLcall("glTexEnvi");
429
430 /* Draw a quad */
431 gl_info->gl_ops.gl.p_glBegin(GL_TRIANGLE_STRIP);
432 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[0]);
433 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->left, dst_rect->top);
434
435 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[1]);
436 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->right, dst_rect->top);
437
438 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[2]);
439 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->left, dst_rect->bottom);
440
441 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[3]);
442 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->right, dst_rect->bottom);
443 gl_info->gl_ops.gl.p_glEnd();
444
445 /* Unbind the texture */
446 context_bind_texture(context, info.bind_target, 0);
447
448 /* We changed the filtering settings on the texture. Inform the
449 * container about this to get the filters reset properly next draw. */
450 if (src_surface->container)
451 {
452 struct wined3d_texture *texture = src_surface->container;
453 texture->texture_rgb.states[WINED3DTEXSTA_MAGFILTER] = WINED3D_TEXF_POINT;
454 texture->texture_rgb.states[WINED3DTEXSTA_MINFILTER] = WINED3D_TEXF_POINT;
455 texture->texture_rgb.states[WINED3DTEXSTA_MIPFILTER] = WINED3D_TEXF_NONE;
456 texture->texture_rgb.states[WINED3DTEXSTA_SRGBTEXTURE] = FALSE;
457 }
458}
459
460/* Works correctly only for <= 4 bpp formats. */
461static void get_color_masks(const struct wined3d_format *format, DWORD *masks)
462{
463 masks[0] = ((1 << format->red_size) - 1) << format->red_offset;
464 masks[1] = ((1 << format->green_size) - 1) << format->green_offset;
465 masks[2] = ((1 << format->blue_size) - 1) << format->blue_offset;
466}
467
468static HRESULT surface_create_dib_section(struct wined3d_surface *surface)
469{
470 const struct wined3d_format *format = surface->resource.format;
471 SYSTEM_INFO sysInfo;
472 BITMAPINFO *b_info;
473 int extraline = 0;
474 DWORD *masks;
475
476 TRACE("surface %p.\n", surface);
477
478 if (!(format->flags & WINED3DFMT_FLAG_GETDC))
479 {
480 WARN("Cannot use GetDC on a %s surface.\n", debug_d3dformat(format->id));
481 return WINED3DERR_INVALIDCALL;
482 }
483
484 switch (format->byte_count)
485 {
486 case 2:
487 case 4:
488 /* Allocate extra space to store the RGB bit masks. */
489 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
490 break;
491
492 case 3:
493 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
494 break;
495
496 default:
497 /* Allocate extra space for a palette. */
498 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
499 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format->byte_count * 8)));
500 break;
501 }
502
503 if (!b_info)
504 return E_OUTOFMEMORY;
505
506 /* Some applications access the surface in via DWORDs, and do not take
507 * the necessary care at the end of the surface. So we need at least
508 * 4 extra bytes at the end of the surface. Check against the page size,
509 * if the last page used for the surface has at least 4 spare bytes we're
510 * safe, otherwise add an extra line to the DIB section. */
511 GetSystemInfo(&sysInfo);
512 if( ((surface->resource.size + 3) % sysInfo.dwPageSize) < 4)
513 {
514 extraline = 1;
515 TRACE("Adding an extra line to the DIB section.\n");
516 }
517
518 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
519 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
520 b_info->bmiHeader.biWidth = wined3d_surface_get_pitch(surface) / format->byte_count;
521 b_info->bmiHeader.biHeight = 0 - surface->resource.height - extraline;
522 b_info->bmiHeader.biSizeImage = (surface->resource.height + extraline)
523 * wined3d_surface_get_pitch(surface);
524 b_info->bmiHeader.biPlanes = 1;
525 b_info->bmiHeader.biBitCount = format->byte_count * 8;
526
527 b_info->bmiHeader.biXPelsPerMeter = 0;
528 b_info->bmiHeader.biYPelsPerMeter = 0;
529 b_info->bmiHeader.biClrUsed = 0;
530 b_info->bmiHeader.biClrImportant = 0;
531
532 /* Get the bit masks */
533 masks = (DWORD *)b_info->bmiColors;
534 switch (surface->resource.format->id)
535 {
536 case WINED3DFMT_B8G8R8_UNORM:
537 b_info->bmiHeader.biCompression = BI_RGB;
538 break;
539
540 case WINED3DFMT_B5G5R5X1_UNORM:
541 case WINED3DFMT_B5G5R5A1_UNORM:
542 case WINED3DFMT_B4G4R4A4_UNORM:
543 case WINED3DFMT_B4G4R4X4_UNORM:
544 case WINED3DFMT_B2G3R3_UNORM:
545 case WINED3DFMT_B2G3R3A8_UNORM:
546 case WINED3DFMT_R10G10B10A2_UNORM:
547 case WINED3DFMT_R8G8B8A8_UNORM:
548 case WINED3DFMT_R8G8B8X8_UNORM:
549 case WINED3DFMT_B10G10R10A2_UNORM:
550 case WINED3DFMT_B5G6R5_UNORM:
551 case WINED3DFMT_R16G16B16A16_UNORM:
552 b_info->bmiHeader.biCompression = BI_BITFIELDS;
553 get_color_masks(format, masks);
554 break;
555
556 default:
557 /* Don't know palette */
558 b_info->bmiHeader.biCompression = BI_RGB;
559 break;
560 }
561
562 TRACE("Creating a DIB section with size %dx%dx%d, size=%d.\n",
563 b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight,
564 b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
565 surface->dib.DIBsection = CreateDIBSection(0, b_info, DIB_RGB_COLORS, &surface->dib.bitmap_data, 0, 0);
566
567 if (!surface->dib.DIBsection)
568 {
569 ERR("Failed to create DIB section.\n");
570 HeapFree(GetProcessHeap(), 0, b_info);
571 return HRESULT_FROM_WIN32(GetLastError());
572 }
573
574 TRACE("DIBSection at %p.\n", surface->dib.bitmap_data);
575 /* Copy the existing surface to the dib section. */
576 if (surface->resource.allocatedMemory)
577 {
578 memcpy(surface->dib.bitmap_data, surface->resource.allocatedMemory,
579 surface->resource.height * wined3d_surface_get_pitch(surface));
580 }
581 else
582 {
583 /* This is to make maps read the GL texture although memory is allocated. */
584 surface->flags &= ~SFLAG_INSYSMEM;
585 }
586 surface->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
587
588 HeapFree(GetProcessHeap(), 0, b_info);
589
590 /* Now allocate a DC. */
591 surface->hDC = CreateCompatibleDC(0);
592 SelectObject(surface->hDC, surface->dib.DIBsection);
593 TRACE("Using wined3d palette %p.\n", surface->palette);
594 SelectPalette(surface->hDC, surface->palette ? surface->palette->hpal : 0, FALSE);
595
596 surface->flags |= SFLAG_DIBSECTION;
597
598 return WINED3D_OK;
599}
600
601static BOOL surface_need_pbo(const struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
602{
603 if (surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
604 return FALSE;
605 if (!(surface->flags & SFLAG_DYNLOCK))
606 return FALSE;
607 if (surface->flags & (SFLAG_CONVERTED | SFLAG_NONPOW2 | SFLAG_PIN_SYSMEM))
608 return FALSE;
609 if (!gl_info->supported[ARB_PIXEL_BUFFER_OBJECT])
610 return FALSE;
611
612 return TRUE;
613}
614
615static void surface_load_pbo(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
616{
617 struct wined3d_context *context;
618 GLenum error;
619
620 context = context_acquire(surface->resource.device, NULL);
621
622 GL_EXTCALL(glGenBuffersARB(1, &surface->pbo));
623 error = gl_info->gl_ops.gl.p_glGetError();
624 if (!surface->pbo || error != GL_NO_ERROR)
625 ERR("Failed to create a PBO with error %s (%#x).\n", debug_glerror(error), error);
626
627 TRACE("Binding PBO %u.\n", surface->pbo);
628
629 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
630 checkGLcall("glBindBufferARB");
631
632 GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->resource.size + 4,
633 surface->resource.allocatedMemory, GL_STREAM_DRAW_ARB));
634 checkGLcall("glBufferDataARB");
635
636 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
637 checkGLcall("glBindBufferARB");
638
639 /* We don't need the system memory anymore and we can't even use it for PBOs. */
640 if (!(surface->flags & SFLAG_CLIENT))
641 {
642 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
643 surface->resource.heapMemory = NULL;
644 }
645 surface->resource.allocatedMemory = NULL;
646 surface->flags |= SFLAG_PBO;
647 context_release(context);
648}
649
650#ifdef VBOX_WITH_WDDM
651static HRESULT d3dfmt_get_conv(const struct wined3d_surface *surface, BOOL need_alpha_ck, BOOL use_texturing,
652 struct wined3d_format *format, enum wined3d_conversion_type *conversion_type);
653
654void surface_setup_location_onopen(struct wined3d_surface *surface)
655{
656 struct wined3d_device *device = surface->resource.device;
657 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
658 DWORD alloc_flag = SFLAG_ALLOCATED;
659// DWORD alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED;
660 enum wined3d_conversion_type convert;
661 struct wined3d_format format;
662
663
664 d3dfmt_get_conv(surface, TRUE, TRUE, &format, &convert);
665 if (convert != WINED3D_CT_NONE || format.convert)
666 surface->flags |= SFLAG_CONVERTED;
667 else surface->flags &= ~SFLAG_CONVERTED;
668
669 if(surface->container)
670 {
671 struct wined3d_context *context = context_acquire(device, NULL);
672 pglChromiumParameteriCR(GL_RCUSAGE_TEXTURE_SET_CR, (GLuint)VBOXSHRC_GET_SHAREHANDLE(surface));
673 context_release(context);
674
675 }
676 /* else -> all should be already set in texture init,
677 * which actually calls the current routine for each of texture's surfaces
678 * for setting up their state */
679
680 surface->flags |= alloc_flag;
681 surface->texture_name = (GLuint)VBOXSHRC_GET_SHAREHANDLE(surface);
682
683 surface_modify_location(surface, SFLAG_INTEXTURE, TRUE);
684}
685#endif
686
687static void surface_prepare_system_memory(struct wined3d_surface *surface)
688{
689 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
690
691 TRACE("surface %p.\n", surface);
692
693 if (!(surface->flags & SFLAG_PBO) && surface_need_pbo(surface, gl_info))
694 surface_load_pbo(surface, gl_info);
695 else if (!(surface->resource.allocatedMemory || surface->flags & SFLAG_PBO))
696 {
697 /* Whatever surface we have, make sure that there is memory allocated
698 * for the downloaded copy, or a PBO to map. */
699 if (!surface->resource.heapMemory)
700 surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), 0, surface->resource.size + RESOURCE_ALIGNMENT);
701
702 surface->resource.allocatedMemory = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory
703 + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
704
705 if (surface->flags & SFLAG_INSYSMEM)
706 ERR("Surface without memory or PBO has SFLAG_INSYSMEM set.\n");
707 }
708}
709
710static void surface_evict_sysmem(struct wined3d_surface *surface)
711{
712 if (surface->resource.map_count || (surface->flags & SFLAG_DONOTFREE))
713 return;
714
715 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
716 surface->resource.allocatedMemory = NULL;
717 surface->resource.heapMemory = NULL;
718 surface_modify_location(surface, SFLAG_INSYSMEM, FALSE);
719}
720
721/* Context activation is done by the caller. */
722static void surface_bind(struct wined3d_surface *surface, struct wined3d_context *context, BOOL srgb)
723{
724 TRACE("surface %p, context %p, srgb %#x.\n", surface, context, srgb);
725
726 if (surface->container)
727 {
728 struct wined3d_texture *texture = surface->container;
729
730 TRACE("Passing to container (%p).\n", texture);
731 texture->texture_ops->texture_bind(texture, context, srgb);
732 }
733 else
734 {
735 const struct wined3d_gl_info *gl_info = context->gl_info;
736
737 if (surface->texture_level)
738 {
739 ERR("Standalone surface %p is non-zero texture level %u.\n",
740 surface, surface->texture_level);
741 }
742
743 if (srgb)
744 ERR("Trying to bind standalone surface %p as sRGB.\n", surface);
745
746 if (!surface->texture_name)
747 {
748#ifdef VBOX_WITH_WDDM
749 if (VBOXSHRC_IS_SHARED_OPENED(surface))
750 {
751 struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
752 ERR("should not be here!");
753 surface->texture_name = (GLuint)VBOXSHRC_GET_SHAREHANDLE(surface);
754 Assert(surface->texture_name);
755 pglChromiumParameteriCR(GL_RCUSAGE_TEXTURE_SET_CR, surface->texture_name);
756 }
757 else
758#endif
759 {
760 gl_info->gl_ops.gl.p_glGenTextures(1, &surface->texture_name);
761 checkGLcall("glGenTextures");
762
763 TRACE("Surface %p given name %u.\n", surface, surface->texture_name);
764
765 context_bind_texture(context, surface->texture_target, surface->texture_name);
766 gl_info->gl_ops.gl.p_glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
767 gl_info->gl_ops.gl.p_glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
768 gl_info->gl_ops.gl.p_glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
769 gl_info->gl_ops.gl.p_glTexParameteri(surface->texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
770 gl_info->gl_ops.gl.p_glTexParameteri(surface->texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
771 checkGLcall("glTexParameteri");
772
773#ifdef VBOX_WITH_WDDM
774 if (VBOXSHRC_IS_SHARED(surface))
775 {
776 VBOXSHRC_SET_SHAREHANDLE(surface, surface->texture_name);
777 }
778#endif
779 }
780 }
781 else
782 {
783 context_bind_texture(context, surface->texture_target, surface->texture_name);
784 }
785
786 }
787}
788
789/* Context activation is done by the caller. */
790static void surface_bind_and_dirtify(struct wined3d_surface *surface,
791 struct wined3d_context *context, BOOL srgb)
792{
793 struct wined3d_device *device = surface->resource.device;
794 DWORD active_sampler;
795
796 /* We don't need a specific texture unit, but after binding the texture
797 * the current unit is dirty. Read the unit back instead of switching to
798 * 0, this avoids messing around with the state manager's GL states. The
799 * current texture unit should always be a valid one.
800 *
801 * To be more specific, this is tricky because we can implicitly be
802 * called from sampler() in state.c. This means we can't touch anything
803 * other than whatever happens to be the currently active texture, or we
804 * would risk marking already applied sampler states dirty again. */
805 active_sampler = device->rev_tex_unit_map[context->active_texture];
806
807#if 0 //def DEBUG_misha
808 {
809 GLint active_texture=GL_TEXTURE0_ARB;
810 glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
811 Assert(active_texture - GL_TEXTURE0_ARB == context->active_texture);
812 }
813#endif
814
815 if (active_sampler != WINED3D_UNMAPPED_STAGE)
816 device_invalidate_state(device, STATE_SAMPLER(active_sampler));
817 surface_bind(surface, context, srgb);
818}
819
820static void surface_force_reload(struct wined3d_surface *surface)
821{
822 surface->flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
823}
824
825static void surface_release_client_storage(struct wined3d_surface *surface)
826{
827 struct wined3d_context *context = context_acquire(surface->resource.device, NULL);
828 const struct wined3d_gl_info *gl_info = context->gl_info;
829
830 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
831 if (surface->texture_name)
832 {
833 surface_bind_and_dirtify(surface, context, FALSE);
834 gl_info->gl_ops.gl.p_glTexImage2D(surface->texture_target, surface->texture_level,
835 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
836 }
837 if (surface->texture_name_srgb)
838 {
839 surface_bind_and_dirtify(surface, context, TRUE);
840 gl_info->gl_ops.gl.p_glTexImage2D(surface->texture_target, surface->texture_level,
841 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
842 }
843 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
844
845 context_release(context);
846
847 surface_modify_location(surface, SFLAG_INSRGBTEX, FALSE);
848 surface_modify_location(surface, SFLAG_INTEXTURE, FALSE);
849 surface_force_reload(surface);
850}
851
852static HRESULT surface_private_setup(struct wined3d_surface *surface)
853{
854 /* TODO: Check against the maximum texture sizes supported by the video card. */
855 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
856 unsigned int pow2Width, pow2Height;
857
858 TRACE("surface %p.\n", surface);
859
860 surface->texture_name = 0;
861 surface->texture_target = GL_TEXTURE_2D;
862
863 /* Non-power2 support */
864 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
865 {
866 pow2Width = surface->resource.width;
867 pow2Height = surface->resource.height;
868 }
869 else
870 {
871 /* Find the nearest pow2 match */
872 pow2Width = pow2Height = 1;
873 while (pow2Width < surface->resource.width)
874 pow2Width <<= 1;
875 while (pow2Height < surface->resource.height)
876 pow2Height <<= 1;
877 }
878 surface->pow2Width = pow2Width;
879 surface->pow2Height = pow2Height;
880
881 if (pow2Width > surface->resource.width || pow2Height > surface->resource.height)
882 {
883 /* TODO: Add support for non power two compressed textures. */
884 if (surface->resource.format->flags & WINED3DFMT_FLAG_COMPRESSED)
885 {
886 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
887 surface, surface->resource.width, surface->resource.height);
888 return WINED3DERR_NOTAVAILABLE;
889 }
890 }
891
892 if (pow2Width != surface->resource.width
893 || pow2Height != surface->resource.height)
894 {
895 surface->flags |= SFLAG_NONPOW2;
896 }
897
898 if ((surface->pow2Width > gl_info->limits.texture_size || surface->pow2Height > gl_info->limits.texture_size)
899 && !(surface->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
900 {
901 /* One of three options:
902 * 1: Do the same as we do with NPOT and scale the texture, (any
903 * texture ops would require the texture to be scaled which is
904 * potentially slow)
905 * 2: Set the texture to the maximum size (bad idea).
906 * 3: WARN and return WINED3DERR_NOTAVAILABLE;
907 * 4: Create the surface, but allow it to be used only for DirectDraw
908 * Blts. Some apps (e.g. Swat 3) create textures with a Height of
909 * 16 and a Width > 3000 and blt 16x16 letter areas from them to
910 * the render target. */
911 if (surface->resource.pool == WINED3D_POOL_DEFAULT || surface->resource.pool == WINED3D_POOL_MANAGED)
912 {
913 WARN("Unable to allocate a surface which exceeds the maximum OpenGL texture size.\n");
914 return WINED3DERR_NOTAVAILABLE;
915 }
916
917 /* We should never use this surface in combination with OpenGL! */
918 TRACE("Creating an oversized surface: %ux%u.\n",
919 surface->pow2Width, surface->pow2Height);
920 }
921 else
922 {
923 /* Don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8
924 * and EXT_PALETTED_TEXTURE is used in combination with texture
925 * uploads (RTL_READTEX/RTL_TEXTEX). The reason is that
926 * EXT_PALETTED_TEXTURE doesn't work in combination with
927 * ARB_TEXTURE_RECTANGLE. */
928 if (surface->flags & SFLAG_NONPOW2 && gl_info->supported[ARB_TEXTURE_RECTANGLE]
929 && !(surface->resource.format->id == WINED3DFMT_P8_UINT
930 && gl_info->supported[EXT_PALETTED_TEXTURE]
931 && wined3d_settings.rendertargetlock_mode == RTL_READTEX))
932 {
933 surface->texture_target = GL_TEXTURE_RECTANGLE_ARB;
934 surface->pow2Width = surface->resource.width;
935 surface->pow2Height = surface->resource.height;
936 surface->flags &= ~(SFLAG_NONPOW2 | SFLAG_NORMCOORD);
937 }
938 }
939
940 switch (wined3d_settings.offscreen_rendering_mode)
941 {
942 case ORM_FBO:
943 surface->get_drawable_size = get_drawable_size_fbo;
944 break;
945
946 case ORM_BACKBUFFER:
947 surface->get_drawable_size = get_drawable_size_backbuffer;
948 break;
949
950 default:
951 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode);
952 return WINED3DERR_INVALIDCALL;
953 }
954
955 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
956 surface->flags |= SFLAG_DISCARDED;
957
958 return WINED3D_OK;
959}
960
961static void surface_realize_palette(struct wined3d_surface *surface)
962{
963 struct wined3d_palette *palette = surface->palette;
964
965 TRACE("surface %p.\n", surface);
966
967 if (!palette) return;
968
969 if (surface->resource.format->id == WINED3DFMT_P8_UINT
970 || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
971 {
972 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
973 {
974 /* Make sure the texture is up to date. This call doesn't do
975 * anything if the texture is already up to date. */
976 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
977
978 /* We want to force a palette refresh, so mark the drawable as not being up to date */
979 if (!surface_is_offscreen(surface))
980 surface_modify_location(surface, SFLAG_INDRAWABLE, FALSE);
981 }
982 else
983 {
984 if (!(surface->flags & SFLAG_INSYSMEM))
985 {
986 TRACE("Palette changed with surface that does not have an up to date system memory copy.\n");
987 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
988 }
989 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
990 }
991 }
992
993 if (surface->flags & SFLAG_DIBSECTION)
994 {
995 RGBQUAD col[256];
996 unsigned int i;
997
998 TRACE("Updating the DC's palette.\n");
999
1000 for (i = 0; i < 256; ++i)
1001 {
1002 col[i].rgbRed = palette->palents[i].peRed;
1003 col[i].rgbGreen = palette->palents[i].peGreen;
1004 col[i].rgbBlue = palette->palents[i].peBlue;
1005 col[i].rgbReserved = 0;
1006 }
1007 SetDIBColorTable(surface->hDC, 0, 256, col);
1008 }
1009
1010 /* Propagate the changes to the drawable when we have a palette. */
1011 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
1012 surface_load_location(surface, surface->draw_binding, NULL);
1013}
1014
1015static HRESULT surface_draw_overlay(struct wined3d_surface *surface)
1016{
1017 HRESULT hr;
1018
1019 /* If there's no destination surface there is nothing to do. */
1020 if (!surface->overlay_dest)
1021 return WINED3D_OK;
1022
1023 /* Blt calls ModifyLocation on the dest surface, which in turn calls
1024 * DrawOverlay to update the overlay. Prevent an endless recursion. */
1025 if (surface->overlay_dest->flags & SFLAG_INOVERLAYDRAW)
1026 return WINED3D_OK;
1027
1028 surface->overlay_dest->flags |= SFLAG_INOVERLAYDRAW;
1029 hr = wined3d_surface_blt(surface->overlay_dest, &surface->overlay_destrect, surface,
1030 &surface->overlay_srcrect, WINEDDBLT_WAIT, NULL, WINED3D_TEXF_LINEAR);
1031 surface->overlay_dest->flags &= ~SFLAG_INOVERLAYDRAW;
1032
1033 return hr;
1034}
1035
1036static void surface_map(struct wined3d_surface *surface, const RECT *rect, DWORD flags)
1037{
1038 struct wined3d_device *device = surface->resource.device;
1039 const RECT *pass_rect = rect;
1040
1041 TRACE("surface %p, rect %s, flags %#x.\n",
1042 surface, wine_dbgstr_rect(rect), flags);
1043
1044 if (flags & WINED3D_MAP_DISCARD)
1045 {
1046 TRACE("WINED3D_MAP_DISCARD flag passed, marking SYSMEM as up to date.\n");
1047 surface_prepare_system_memory(surface);
1048 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
1049 }
1050 else
1051 {
1052 if (surface->resource.usage & WINED3DUSAGE_DYNAMIC)
1053 WARN_(d3d_perf)("Mapping a dynamic surface without WINED3D_MAP_DISCARD.\n");
1054
1055 /* surface_load_location() does not check if the rectangle specifies
1056 * the full surface. Most callers don't need that, so do it here. */
1057 if (rect && !rect->top && !rect->left
1058 && rect->right == surface->resource.width
1059 && rect->bottom == surface->resource.height)
1060 pass_rect = NULL;
1061 surface_load_location(surface, SFLAG_INSYSMEM, pass_rect);
1062 }
1063
1064 if (surface->flags & SFLAG_PBO)
1065 {
1066 const struct wined3d_gl_info *gl_info;
1067 struct wined3d_context *context;
1068
1069 context = context_acquire(device, NULL);
1070 gl_info = context->gl_info;
1071
1072 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
1073 checkGLcall("glBindBufferARB");
1074
1075 /* This shouldn't happen but could occur if some other function
1076 * didn't handle the PBO properly. */
1077 if (surface->resource.allocatedMemory)
1078 ERR("The surface already has PBO memory allocated.\n");
1079
1080 surface->resource.allocatedMemory = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
1081 checkGLcall("glMapBufferARB");
1082
1083 /* Make sure the PBO isn't set anymore in order not to break non-PBO
1084 * calls. */
1085 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1086 checkGLcall("glBindBufferARB");
1087
1088 context_release(context);
1089 }
1090
1091 if (!(flags & (WINED3D_MAP_NO_DIRTY_UPDATE | WINED3D_MAP_READONLY)))
1092 {
1093 if (!rect)
1094 surface_add_dirty_rect(surface, NULL);
1095 else
1096 {
1097 struct wined3d_box b;
1098
1099 b.left = rect->left;
1100 b.top = rect->top;
1101 b.right = rect->right;
1102 b.bottom = rect->bottom;
1103 b.front = 0;
1104 b.back = 1;
1105 surface_add_dirty_rect(surface, &b);
1106 }
1107 }
1108}
1109
1110static void surface_unmap(struct wined3d_surface *surface)
1111{
1112 struct wined3d_device *device = surface->resource.device;
1113 BOOL fullsurface;
1114
1115 TRACE("surface %p.\n", surface);
1116
1117 memset(&surface->lockedRect, 0, sizeof(surface->lockedRect));
1118
1119 if (surface->flags & SFLAG_PBO)
1120 {
1121 const struct wined3d_gl_info *gl_info;
1122 struct wined3d_context *context;
1123
1124 TRACE("Freeing PBO memory.\n");
1125
1126 context = context_acquire(device, NULL);
1127 gl_info = context->gl_info;
1128
1129 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
1130 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
1131 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1132 checkGLcall("glUnmapBufferARB");
1133 context_release(context);
1134
1135 surface->resource.allocatedMemory = NULL;
1136 }
1137
1138 TRACE("dirtyfied %u.\n", surface->flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1);
1139
1140 if (surface->flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE))
1141 {
1142 TRACE("Not dirtified, nothing to do.\n");
1143 goto done;
1144 }
1145
1146 if (surface->swapchain && surface->swapchain->front_buffer == surface)
1147 {
1148 if (!surface->dirtyRect.left && !surface->dirtyRect.top
1149 && surface->dirtyRect.right == surface->resource.width
1150 && surface->dirtyRect.bottom == surface->resource.height)
1151 {
1152 fullsurface = TRUE;
1153 }
1154 else
1155 {
1156 /* TODO: Proper partial rectangle tracking. */
1157 fullsurface = FALSE;
1158 surface->flags |= SFLAG_INSYSMEM;
1159 }
1160
1161 surface_load_location(surface, surface->draw_binding, fullsurface ? NULL : &surface->dirtyRect);
1162
1163 /* Partial rectangle tracking is not commonly implemented, it is only
1164 * done for render targets. INSYSMEM was set before to tell
1165 * surface_load_location() where to read the rectangle from.
1166 * Indrawable is set because all modifications from the partial
1167 * sysmem copy are written back to the drawable, thus the surface is
1168 * merged again in the drawable. The sysmem copy is not fully up to
1169 * date because only a subrectangle was read in Map(). */
1170 if (!fullsurface)
1171 {
1172 surface_modify_location(surface, surface->draw_binding, TRUE);
1173 surface_evict_sysmem(surface);
1174 }
1175
1176 surface->dirtyRect.left = surface->resource.width;
1177 surface->dirtyRect.top = surface->resource.height;
1178 surface->dirtyRect.right = 0;
1179 surface->dirtyRect.bottom = 0;
1180 }
1181 else if (surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))
1182 {
1183 FIXME("Depth / stencil buffer locking is not implemented.\n");
1184 }
1185
1186done:
1187 /* Overlays have to be redrawn manually after changes with the GL implementation */
1188 if (surface->overlay_dest)
1189 surface_draw_overlay(surface);
1190}
1191
1192static BOOL surface_is_full_rect(const struct wined3d_surface *surface, const RECT *r)
1193{
1194 if ((r->left && r->right) || abs(r->right - r->left) != surface->resource.width)
1195 return FALSE;
1196 if ((r->top && r->bottom) || abs(r->bottom - r->top) != surface->resource.height)
1197 return FALSE;
1198 return TRUE;
1199}
1200
1201static void surface_depth_blt_fbo(const struct wined3d_device *device,
1202 struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect,
1203 struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect)
1204{
1205 const struct wined3d_gl_info *gl_info;
1206 struct wined3d_context *context;
1207 DWORD src_mask, dst_mask;
1208 GLbitfield gl_mask;
1209
1210 TRACE("device %p\n", device);
1211 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
1212 src_surface, debug_surflocation(src_location), wine_dbgstr_rect(src_rect));
1213 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
1214 dst_surface, debug_surflocation(dst_location), wine_dbgstr_rect(dst_rect));
1215
1216 src_mask = src_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
1217 dst_mask = dst_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
1218
1219 if (src_mask != dst_mask)
1220 {
1221 ERR("Incompatible formats %s and %s.\n",
1222 debug_d3dformat(src_surface->resource.format->id),
1223 debug_d3dformat(dst_surface->resource.format->id));
1224 return;
1225 }
1226
1227 if (!src_mask)
1228 {
1229 ERR("Not a depth / stencil format: %s.\n",
1230 debug_d3dformat(src_surface->resource.format->id));
1231 return;
1232 }
1233
1234 gl_mask = 0;
1235 if (src_mask & WINED3DFMT_FLAG_DEPTH)
1236 gl_mask |= GL_DEPTH_BUFFER_BIT;
1237 if (src_mask & WINED3DFMT_FLAG_STENCIL)
1238 gl_mask |= GL_STENCIL_BUFFER_BIT;
1239
1240 /* Make sure the locations are up-to-date. Loading the destination
1241 * surface isn't required if the entire surface is overwritten. */
1242 surface_load_location(src_surface, src_location, NULL);
1243 if (!surface_is_full_rect(dst_surface, dst_rect))
1244 surface_load_location(dst_surface, dst_location, NULL);
1245
1246 context = context_acquire(device, NULL);
1247 if (!context->valid)
1248 {
1249 context_release(context);
1250 WARN("Invalid context, skipping blit.\n");
1251 return;
1252 }
1253
1254 gl_info = context->gl_info;
1255
1256 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, NULL, src_surface, src_location);
1257 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
1258
1259 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, NULL, dst_surface, dst_location);
1260 context_set_draw_buffer(context, GL_NONE);
1261 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
1262 context_invalidate_state(context, STATE_FRAMEBUFFER);
1263
1264 if (gl_mask & GL_DEPTH_BUFFER_BIT)
1265 {
1266 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
1267 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ZWRITEENABLE));
1268 }
1269 if (gl_mask & GL_STENCIL_BUFFER_BIT)
1270 {
1271 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
1272 {
1273 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1274 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE));
1275 }
1276 gl_info->gl_ops.gl.p_glStencilMask(~0U);
1277 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
1278 }
1279
1280 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
1281 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
1282
1283 gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom,
1284 dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, gl_mask, GL_NEAREST);
1285 checkGLcall("glBlitFramebuffer()");
1286
1287 if (wined3d_settings.strict_draw_ordering)
1288 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
1289
1290 context_release(context);
1291}
1292
1293/* Blit between surface locations. Onscreen on different swapchains is not supported.
1294 * Depth / stencil is not supported. */
1295static void surface_blt_fbo(const struct wined3d_device *device, enum wined3d_texture_filter_type filter,
1296 struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect_in,
1297 struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect_in)
1298{
1299 const struct wined3d_gl_info *gl_info;
1300 struct wined3d_context *context;
1301 RECT src_rect, dst_rect;
1302 GLenum gl_filter;
1303 GLenum buffer;
1304
1305 TRACE("device %p, filter %s,\n", device, debug_d3dtexturefiltertype(filter));
1306 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
1307 src_surface, debug_surflocation(src_location), wine_dbgstr_rect(src_rect_in));
1308 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
1309 dst_surface, debug_surflocation(dst_location), wine_dbgstr_rect(dst_rect_in));
1310
1311 src_rect = *src_rect_in;
1312 dst_rect = *dst_rect_in;
1313
1314 switch (filter)
1315 {
1316 case WINED3D_TEXF_LINEAR:
1317 gl_filter = GL_LINEAR;
1318 break;
1319
1320 default:
1321 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter), filter);
1322 case WINED3D_TEXF_NONE:
1323 case WINED3D_TEXF_POINT:
1324 gl_filter = GL_NEAREST;
1325 break;
1326 }
1327
1328 /* Resolve the source surface first if needed. */
1329 if (src_location == SFLAG_INRB_MULTISAMPLE
1330 && (src_surface->resource.format->id != dst_surface->resource.format->id
1331 || abs(src_rect.bottom - src_rect.top) != abs(dst_rect.bottom - dst_rect.top)
1332 || abs(src_rect.right - src_rect.left) != abs(dst_rect.right - dst_rect.left)))
1333 src_location = SFLAG_INRB_RESOLVED;
1334
1335 /* Make sure the locations are up-to-date. Loading the destination
1336 * surface isn't required if the entire surface is overwritten. (And is
1337 * in fact harmful if we're being called by surface_load_location() with
1338 * the purpose of loading the destination surface.) */
1339 surface_load_location(src_surface, src_location, NULL);
1340 if (!surface_is_full_rect(dst_surface, &dst_rect))
1341 surface_load_location(dst_surface, dst_location, NULL);
1342
1343 if (src_location == SFLAG_INDRAWABLE) context = context_acquire(device, src_surface);
1344 else if (dst_location == SFLAG_INDRAWABLE) context = context_acquire(device, dst_surface);
1345 else context = context_acquire(device, NULL);
1346
1347 if (!context->valid)
1348 {
1349 context_release(context);
1350 WARN("Invalid context, skipping blit.\n");
1351 return;
1352 }
1353
1354 gl_info = context->gl_info;
1355
1356 if (src_location == SFLAG_INDRAWABLE)
1357 {
1358 TRACE("Source surface %p is onscreen.\n", src_surface);
1359 buffer = surface_get_gl_buffer(src_surface);
1360#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
1361 surface_translate_drawable_coords(src_surface, context->win_handle, &src_rect);
1362#else
1363 surface_translate_drawable_coords(src_surface, context->swapchain->win_handle, &src_rect);
1364#endif
1365 }
1366 else
1367 {
1368 TRACE("Source surface %p is offscreen.\n", src_surface);
1369 buffer = GL_COLOR_ATTACHMENT0;
1370 }
1371
1372 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, src_surface, NULL, src_location);
1373 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
1374 checkGLcall("glReadBuffer()");
1375 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
1376
1377 if (dst_location == SFLAG_INDRAWABLE)
1378 {
1379 TRACE("Destination surface %p is onscreen.\n", dst_surface);
1380 buffer = surface_get_gl_buffer(dst_surface);
1381#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
1382 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
1383#else
1384 surface_translate_drawable_coords(dst_surface, context->swapchain->win_handle, &dst_rect);
1385#endif
1386 }
1387 else
1388 {
1389 TRACE("Destination surface %p is offscreen.\n", dst_surface);
1390 buffer = GL_COLOR_ATTACHMENT0;
1391 }
1392
1393 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, dst_surface, NULL, dst_location);
1394 context_set_draw_buffer(context, buffer);
1395 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
1396 context_invalidate_state(context, STATE_FRAMEBUFFER);
1397
1398 gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1399 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE));
1400 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1));
1401 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2));
1402 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3));
1403
1404 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
1405 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
1406
1407 gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
1408 dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, GL_COLOR_BUFFER_BIT, gl_filter);
1409 checkGLcall("glBlitFramebuffer()");
1410
1411 if (wined3d_settings.strict_draw_ordering
1412 || (dst_location == SFLAG_INDRAWABLE
1413 && dst_surface->swapchain->front_buffer == dst_surface))
1414 gl_info->gl_ops.gl.p_glFlush();
1415
1416 context_release(context);
1417}
1418
1419static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
1420 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
1421 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
1422{
1423 if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
1424 return FALSE;
1425
1426 /* Source and/or destination need to be on the GL side */
1427 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
1428 return FALSE;
1429
1430 switch (blit_op)
1431 {
1432 case WINED3D_BLIT_OP_COLOR_BLIT:
1433 if (!((src_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (src_usage & WINED3DUSAGE_RENDERTARGET)))
1434 return FALSE;
1435 if (!((dst_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
1436 return FALSE;
1437 break;
1438
1439 case WINED3D_BLIT_OP_DEPTH_BLIT:
1440 if (!(src_format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
1441 return FALSE;
1442 if (!(dst_format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
1443 return FALSE;
1444 break;
1445
1446 default:
1447 return FALSE;
1448 }
1449
1450 if (!(src_format->id == dst_format->id
1451 || (is_identity_fixup(src_format->color_fixup)
1452 && is_identity_fixup(dst_format->color_fixup))))
1453 return FALSE;
1454
1455 return TRUE;
1456}
1457
1458/* This function checks if the primary render target uses the 8bit paletted format. */
1459static BOOL primary_render_target_is_p8(const struct wined3d_device *device)
1460{
1461 if (device->fb.render_targets && device->fb.render_targets[0])
1462 {
1463 const struct wined3d_surface *render_target = device->fb.render_targets[0];
1464 if ((render_target->resource.usage & WINED3DUSAGE_RENDERTARGET)
1465 && (render_target->resource.format->id == WINED3DFMT_P8_UINT))
1466 return TRUE;
1467 }
1468 return FALSE;
1469}
1470
1471static BOOL surface_convert_color_to_float(const struct wined3d_surface *surface,
1472 DWORD color, struct wined3d_color *float_color)
1473{
1474 const struct wined3d_format *format = surface->resource.format;
1475 const struct wined3d_device *device = surface->resource.device;
1476
1477 switch (format->id)
1478 {
1479 case WINED3DFMT_P8_UINT:
1480 if (surface->palette)
1481 {
1482 float_color->r = surface->palette->palents[color].peRed / 255.0f;
1483 float_color->g = surface->palette->palents[color].peGreen / 255.0f;
1484 float_color->b = surface->palette->palents[color].peBlue / 255.0f;
1485 }
1486 else
1487 {
1488 float_color->r = 0.0f;
1489 float_color->g = 0.0f;
1490 float_color->b = 0.0f;
1491 }
1492 float_color->a = primary_render_target_is_p8(device) ? color / 255.0f : 1.0f;
1493 break;
1494
1495 case WINED3DFMT_B5G6R5_UNORM:
1496 float_color->r = ((color >> 11) & 0x1f) / 31.0f;
1497 float_color->g = ((color >> 5) & 0x3f) / 63.0f;
1498 float_color->b = (color & 0x1f) / 31.0f;
1499 float_color->a = 1.0f;
1500 break;
1501
1502 case WINED3DFMT_B8G8R8_UNORM:
1503 case WINED3DFMT_B8G8R8X8_UNORM:
1504 float_color->r = D3DCOLOR_R(color);
1505 float_color->g = D3DCOLOR_G(color);
1506 float_color->b = D3DCOLOR_B(color);
1507 float_color->a = 1.0f;
1508 break;
1509
1510 case WINED3DFMT_B8G8R8A8_UNORM:
1511 float_color->r = D3DCOLOR_R(color);
1512 float_color->g = D3DCOLOR_G(color);
1513 float_color->b = D3DCOLOR_B(color);
1514 float_color->a = D3DCOLOR_A(color);
1515 break;
1516
1517 default:
1518 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format->id));
1519 return FALSE;
1520 }
1521
1522 return TRUE;
1523}
1524
1525static BOOL surface_convert_depth_to_float(const struct wined3d_surface *surface, DWORD depth, float *float_depth)
1526{
1527 const struct wined3d_format *format = surface->resource.format;
1528
1529 switch (format->id)
1530 {
1531 case WINED3DFMT_S1_UINT_D15_UNORM:
1532 *float_depth = depth / (float)0x00007fff;
1533 break;
1534
1535 case WINED3DFMT_D16_UNORM:
1536 *float_depth = depth / (float)0x0000ffff;
1537 break;
1538
1539 case WINED3DFMT_D24_UNORM_S8_UINT:
1540 case WINED3DFMT_X8D24_UNORM:
1541 *float_depth = depth / (float)0x00ffffff;
1542 break;
1543
1544 case WINED3DFMT_D32_UNORM:
1545 *float_depth = depth / (float)0xffffffff;
1546 break;
1547
1548 default:
1549 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format->id));
1550 return FALSE;
1551 }
1552
1553 return TRUE;
1554}
1555
1556/* Do not call while under the GL lock. */
1557static HRESULT wined3d_surface_depth_fill(struct wined3d_surface *surface, const RECT *rect, float depth)
1558{
1559 const struct wined3d_resource *resource = &surface->resource;
1560 struct wined3d_device *device = resource->device;
1561 const struct blit_shader *blitter;
1562
1563 blitter = wined3d_select_blitter(&device->adapter->gl_info, WINED3D_BLIT_OP_DEPTH_FILL,
1564 NULL, 0, 0, NULL, rect, resource->usage, resource->pool, resource->format);
1565 if (!blitter)
1566 {
1567 FIXME("No blitter is capable of performing the requested depth fill operation.\n");
1568 return WINED3DERR_INVALIDCALL;
1569 }
1570
1571 return blitter->depth_fill(device, surface, rect, depth);
1572}
1573
1574static HRESULT wined3d_surface_depth_blt(struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect,
1575 struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect)
1576{
1577 struct wined3d_device *device = src_surface->resource.device;
1578
1579 if (!fbo_blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_DEPTH_BLIT,
1580 src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
1581 dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
1582 return WINED3DERR_INVALIDCALL;
1583
1584 surface_depth_blt_fbo(device, src_surface, src_location, src_rect, dst_surface, dst_location, dst_rect);
1585
1586 surface_modify_ds_location(dst_surface, dst_location,
1587 dst_surface->ds_current_size.cx, dst_surface->ds_current_size.cy);
1588
1589 return WINED3D_OK;
1590}
1591
1592/* Do not call while under the GL lock. */
1593HRESULT CDECL wined3d_surface_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect_in,
1594 struct wined3d_surface *src_surface, const RECT *src_rect_in, DWORD flags,
1595 const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter)
1596{
1597 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
1598 struct wined3d_device *device = dst_surface->resource.device;
1599 DWORD src_ds_flags, dst_ds_flags;
1600 RECT src_rect, dst_rect;
1601 BOOL scale, convert;
1602#ifdef VBOX_WITH_WDDM
1603 HRESULT hr = WINED3D_OK;
1604#endif
1605
1606 static const DWORD simple_blit = WINEDDBLT_ASYNC
1607 | WINEDDBLT_COLORFILL
1608 | WINEDDBLT_WAIT
1609 | WINEDDBLT_DEPTHFILL
1610 | WINEDDBLT_DONOTWAIT;
1611
1612 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
1613 dst_surface, wine_dbgstr_rect(dst_rect_in), src_surface, wine_dbgstr_rect(src_rect_in),
1614 flags, fx, debug_d3dtexturefiltertype(filter));
1615 TRACE("Usage is %s.\n", debug_d3dusage(dst_surface->resource.usage));
1616
1617 if (fx)
1618 {
1619 TRACE("dwSize %#x.\n", fx->dwSize);
1620 TRACE("dwDDFX %#x.\n", fx->dwDDFX);
1621 TRACE("dwROP %#x.\n", fx->dwROP);
1622 TRACE("dwDDROP %#x.\n", fx->dwDDROP);
1623 TRACE("dwRotationAngle %#x.\n", fx->dwRotationAngle);
1624 TRACE("dwZBufferOpCode %#x.\n", fx->dwZBufferOpCode);
1625 TRACE("dwZBufferLow %#x.\n", fx->dwZBufferLow);
1626 TRACE("dwZBufferHigh %#x.\n", fx->dwZBufferHigh);
1627 TRACE("dwZBufferBaseDest %#x.\n", fx->dwZBufferBaseDest);
1628 TRACE("dwZDestConstBitDepth %#x.\n", fx->dwZDestConstBitDepth);
1629 TRACE("lpDDSZBufferDest %p.\n", fx->u1.lpDDSZBufferDest);
1630 TRACE("dwZSrcConstBitDepth %#x.\n", fx->dwZSrcConstBitDepth);
1631 TRACE("lpDDSZBufferSrc %p.\n", fx->u2.lpDDSZBufferSrc);
1632 TRACE("dwAlphaEdgeBlendBitDepth %#x.\n", fx->dwAlphaEdgeBlendBitDepth);
1633 TRACE("dwAlphaEdgeBlend %#x.\n", fx->dwAlphaEdgeBlend);
1634 TRACE("dwReserved %#x.\n", fx->dwReserved);
1635 TRACE("dwAlphaDestConstBitDepth %#x.\n", fx->dwAlphaDestConstBitDepth);
1636 TRACE("lpDDSAlphaDest %p.\n", fx->u3.lpDDSAlphaDest);
1637 TRACE("dwAlphaSrcConstBitDepth %#x.\n", fx->dwAlphaSrcConstBitDepth);
1638 TRACE("lpDDSAlphaSrc %p.\n", fx->u4.lpDDSAlphaSrc);
1639 TRACE("lpDDSPattern %p.\n", fx->u5.lpDDSPattern);
1640 TRACE("ddckDestColorkey {%#x, %#x}.\n",
1641 fx->ddckDestColorkey.color_space_low_value,
1642 fx->ddckDestColorkey.color_space_high_value);
1643 TRACE("ddckSrcColorkey {%#x, %#x}.\n",
1644 fx->ddckSrcColorkey.color_space_low_value,
1645 fx->ddckSrcColorkey.color_space_high_value);
1646 }
1647
1648 if (dst_surface->resource.map_count || (src_surface && src_surface->resource.map_count))
1649 {
1650 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
1651 return WINEDDERR_SURFACEBUSY;
1652 }
1653
1654 surface_get_rect(dst_surface, dst_rect_in, &dst_rect);
1655
1656 if (dst_rect.left >= dst_rect.right || dst_rect.top >= dst_rect.bottom
1657 || dst_rect.left > dst_surface->resource.width || dst_rect.left < 0
1658 || dst_rect.top > dst_surface->resource.height || dst_rect.top < 0
1659 || dst_rect.right > dst_surface->resource.width || dst_rect.right < 0
1660 || dst_rect.bottom > dst_surface->resource.height || dst_rect.bottom < 0)
1661 {
1662 WARN("The application gave us a bad destination rectangle.\n");
1663 return WINEDDERR_INVALIDRECT;
1664 }
1665
1666 if (src_surface)
1667 {
1668 surface_get_rect(src_surface, src_rect_in, &src_rect);
1669
1670 if (src_rect.left >= src_rect.right || src_rect.top >= src_rect.bottom
1671 || src_rect.left > src_surface->resource.width || src_rect.left < 0
1672 || src_rect.top > src_surface->resource.height || src_rect.top < 0
1673 || src_rect.right > src_surface->resource.width || src_rect.right < 0
1674 || src_rect.bottom > src_surface->resource.height || src_rect.bottom < 0)
1675 {
1676 WARN("Application gave us bad source rectangle for Blt.\n");
1677 return WINEDDERR_INVALIDRECT;
1678 }
1679 }
1680 else
1681 {
1682 memset(&src_rect, 0, sizeof(src_rect));
1683 }
1684
1685#ifdef VBOX_WITH_WDDM
1686 surface_shrc_lock(dst_surface);
1687 if (src_surface) surface_shrc_lock(src_surface);
1688
1689 /* once we've done locking, we should do unlock on exit,
1690 * do goto post_process instead of return below! */
1691#endif
1692
1693 if (!fx || !(fx->dwDDFX))
1694 flags &= ~WINEDDBLT_DDFX;
1695
1696 if (flags & WINEDDBLT_WAIT)
1697 flags &= ~WINEDDBLT_WAIT;
1698
1699 if (flags & WINEDDBLT_ASYNC)
1700 {
1701 static unsigned int once;
1702
1703 if (!once++)
1704 FIXME("Can't handle WINEDDBLT_ASYNC flag.\n");
1705 flags &= ~WINEDDBLT_ASYNC;
1706 }
1707
1708 /* WINEDDBLT_DONOTWAIT appeared in DX7. */
1709 if (flags & WINEDDBLT_DONOTWAIT)
1710 {
1711 static unsigned int once;
1712
1713 if (!once++)
1714 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag.\n");
1715 flags &= ~WINEDDBLT_DONOTWAIT;
1716 }
1717
1718 if (!device->d3d_initialized)
1719 {
1720 WARN("D3D not initialized, using fallback.\n");
1721 goto cpu;
1722 }
1723
1724 /* We want to avoid invalidating the sysmem location for converted
1725 * surfaces, since otherwise we'd have to convert the data back when
1726 * locking them. */
1727 if (dst_surface->flags & SFLAG_CONVERTED)
1728 {
1729 WARN_(d3d_perf)("Converted surface, using CPU blit.\n");
1730#ifndef VBOX_WITH_WDDM
1731 return surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter);
1732#else
1733 hr = surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter);
1734 goto post_process;
1735#endif
1736
1737 }
1738
1739 if (flags & ~simple_blit)
1740 {
1741 WARN_(d3d_perf)("Using fallback for complex blit (%#x).\n", flags);
1742 goto fallback;
1743 }
1744
1745 if (src_surface)
1746 src_swapchain = src_surface->swapchain;
1747 else
1748 src_swapchain = NULL;
1749
1750 dst_swapchain = dst_surface->swapchain;
1751
1752 /* This isn't strictly needed. FBO blits for example could deal with
1753 * cross-swapchain blits by first downloading the source to a texture
1754 * before switching to the destination context. We just have this here to
1755 * not have to deal with the issue, since cross-swapchain blits should be
1756 * rare. */
1757 if (src_swapchain && dst_swapchain && src_swapchain != dst_swapchain)
1758 {
1759 FIXME("Using fallback for cross-swapchain blit.\n");
1760 goto fallback;
1761 }
1762
1763 scale = src_surface
1764 && (src_rect.right - src_rect.left != dst_rect.right - dst_rect.left
1765 || src_rect.bottom - src_rect.top != dst_rect.bottom - dst_rect.top);
1766 convert = src_surface && src_surface->resource.format->id != dst_surface->resource.format->id;
1767
1768 dst_ds_flags = dst_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
1769 if (src_surface)
1770 src_ds_flags = src_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
1771 else
1772 src_ds_flags = 0;
1773
1774 if (src_ds_flags || dst_ds_flags)
1775 {
1776 if (flags & WINEDDBLT_DEPTHFILL)
1777 {
1778 float depth;
1779
1780 TRACE("Depth fill.\n");
1781
1782 if (!surface_convert_depth_to_float(dst_surface, fx->u5.dwFillDepth, &depth))
1783#ifndef VBOX_WITH_WDDM
1784 return WINED3DERR_INVALIDCALL;
1785#else
1786 {
1787 hr = WINED3DERR_INVALIDCALL;
1788 goto post_process;
1789 }
1790#endif
1791
1792 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface, &dst_rect, depth)))
1793#ifndef VBOX_WITH_WDDM
1794 return WINED3D_OK;
1795#else
1796 {
1797 hr = WINED3D_OK;
1798 goto post_process;
1799 }
1800#endif
1801 }
1802 else
1803 {
1804 if (src_ds_flags != dst_ds_flags)
1805 {
1806 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
1807#ifndef VBOX_WITH_WDDM
1808 return WINED3DERR_INVALIDCALL;
1809#else
1810 hr = WINED3D_OK;
1811 goto post_process;
1812#endif
1813 }
1814
1815 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface, src_surface->draw_binding, &src_rect,
1816 dst_surface, dst_surface->draw_binding, &dst_rect)))
1817#ifndef VBOX_WITH_WDDM
1818 return WINED3D_OK;
1819#else
1820 {
1821 hr = WINED3D_OK;
1822 goto post_process;
1823 }
1824#endif
1825 }
1826 }
1827 else
1828 {
1829 /* In principle this would apply to depth blits as well, but we don't
1830 * implement those in the CPU blitter at the moment. */
1831 if ((dst_surface->flags & SFLAG_INSYSMEM)
1832 && (!src_surface || (src_surface->flags & SFLAG_INSYSMEM)))
1833 {
1834#ifdef DEBUG_misha
1835 /* if below condition is not specified, i.e. both surfaces are in tecxture locations,
1836 * we would perhaps need to fallback to tex->tex hw blitting */
1837 Assert(!(dst_surface->flags & SFLAG_INTEXTURE) ||
1838 !src_surface || !(src_surface->flags & SFLAG_INTEXTURE));
1839#endif
1840 if (scale)
1841 TRACE("Not doing sysmem blit because of scaling.\n");
1842 else if (convert)
1843 TRACE("Not doing sysmem blit because of format conversion.\n");
1844 else
1845#ifndef VBOX_WITH_WDDM
1846 return surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter);
1847#else
1848 {
1849 hr = surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter);
1850 goto post_process;
1851 }
1852#endif
1853
1854 }
1855
1856 if (flags & WINEDDBLT_COLORFILL)
1857 {
1858 struct wined3d_color color;
1859
1860 TRACE("Color fill.\n");
1861
1862 if (!surface_convert_color_to_float(dst_surface, fx->u5.dwFillColor, &color))
1863 goto fallback;
1864
1865 if (SUCCEEDED(surface_color_fill(dst_surface, &dst_rect, &color)))
1866#ifndef VBOX_WITH_WDDM
1867 return WINED3D_OK;
1868#else
1869 {
1870 hr = WINED3D_OK;
1871 goto post_process;
1872 }
1873#endif
1874 }
1875 else
1876 {
1877 TRACE("Color blit.\n");
1878
1879 /* Upload */
1880 if ((src_surface->flags & SFLAG_INSYSMEM) && !(dst_surface->flags & SFLAG_INSYSMEM))
1881 {
1882 if (scale)
1883 TRACE("Not doing upload because of scaling.\n");
1884 else if (convert)
1885 TRACE("Not doing upload because of format conversion.\n");
1886 else
1887 {
1888 POINT dst_point = {dst_rect.left, dst_rect.top};
1889
1890 if (SUCCEEDED(surface_upload_from_surface(dst_surface, &dst_point, src_surface, &src_rect)))
1891 {
1892 if (!surface_is_offscreen(dst_surface))
1893 surface_load_location(dst_surface, dst_surface->draw_binding, NULL);
1894#ifndef VBOX_WITH_WDDM
1895 return WINED3D_OK;
1896#else
1897 hr = WINED3D_OK;
1898 goto post_process;
1899#endif
1900 }
1901 }
1902 }
1903
1904 /* Use present for back -> front blits. The idea behind this is
1905 * that present is potentially faster than a blit, in particular
1906 * when FBO blits aren't available. Some ddraw applications like
1907 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
1908 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
1909 * applications can't blit directly to the frontbuffer. */
1910 if (dst_swapchain && dst_swapchain->back_buffers
1911 && dst_surface == dst_swapchain->front_buffer
1912 && src_surface == dst_swapchain->back_buffers[0])
1913 {
1914 enum wined3d_swap_effect swap_effect = dst_swapchain->desc.swap_effect;
1915
1916 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
1917
1918 /* Set the swap effect to COPY, we don't want the backbuffer
1919 * to become undefined. */
1920 dst_swapchain->desc.swap_effect = WINED3D_SWAP_EFFECT_COPY;
1921 wined3d_swapchain_present(dst_swapchain, NULL, NULL, dst_swapchain->win_handle, NULL, 0);
1922 dst_swapchain->desc.swap_effect = swap_effect;
1923
1924#ifndef VBOX_WITH_WDDM
1925 return WINED3D_OK;
1926#else
1927 hr = WINED3D_OK;
1928 goto post_process;
1929#endif
1930 }
1931
1932 if (fbo_blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
1933 &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
1934 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
1935 {
1936 TRACE("Using FBO blit.\n");
1937
1938 surface_blt_fbo(device, filter,
1939 src_surface, src_surface->draw_binding, &src_rect,
1940 dst_surface, dst_surface->draw_binding, &dst_rect);
1941 surface_modify_location(dst_surface, dst_surface->draw_binding, TRUE);
1942#ifndef VBOX_WITH_WDDM
1943 return WINED3D_OK;
1944#else
1945 hr = WINED3D_OK;
1946 goto post_process;
1947#endif
1948 }
1949
1950 if (arbfp_blit.blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
1951 &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
1952 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
1953 {
1954 TRACE("Using arbfp blit.\n");
1955
1956 if (SUCCEEDED(arbfp_blit_surface(device, filter, src_surface, &src_rect, dst_surface, &dst_rect)))
1957#ifndef VBOX_WITH_WDDM
1958 return WINED3D_OK;
1959#else
1960 {
1961 hr = WINED3D_OK;
1962 goto post_process;
1963 }
1964#endif
1965 }
1966 }
1967 }
1968
1969fallback:
1970
1971#ifdef DEBUG_misha
1972 /* test ! */
1973 Assert(0);
1974#endif
1975 /* Special cases for render targets. */
1976 if ((dst_surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
1977 || (src_surface && (src_surface->resource.usage & WINED3DUSAGE_RENDERTARGET)))
1978 {
1979 if (SUCCEEDED(IWineD3DSurfaceImpl_BltOverride(dst_surface, &dst_rect,
1980 src_surface, &src_rect, flags, fx, filter)))
1981#ifndef VBOX_WITH_WDDM
1982 return WINED3D_OK;
1983#else
1984 {
1985 hr = WINED3D_OK;
1986 goto post_process;
1987 }
1988#endif
1989 }
1990
1991cpu:
1992
1993#ifdef DEBUG_misha
1994 /* test ! */
1995 Assert(0);
1996#endif
1997
1998
1999 /* For the rest call the X11 surface implementation. For render targets
2000 * this should be implemented OpenGL accelerated in BltOverride, other
2001 * blits are rather rare. */
2002#ifndef VBOX_WITH_WDDM
2003 return surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter);
2004#else
2005 hr = surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter);
2006 goto post_process;
2007#endif
2008
2009#ifdef VBOX_WITH_WDDM
2010post_process:
2011 surface_shrc_unlock(dst_surface);
2012 if (src_surface) surface_shrc_unlock(src_surface);
2013 return hr;
2014#endif
2015}
2016
2017HRESULT CDECL wined3d_surface_get_render_target_data(struct wined3d_surface *surface,
2018 struct wined3d_surface *render_target)
2019{
2020 TRACE("surface %p, render_target %p.\n", surface, render_target);
2021
2022 /* TODO: Check surface sizes, pools, etc. */
2023
2024 if (render_target->resource.multisample_type)
2025 return WINED3DERR_INVALIDCALL;
2026
2027 return wined3d_surface_blt(surface, NULL, render_target, NULL, 0, NULL, WINED3D_TEXF_POINT);
2028}
2029
2030/* Context activation is done by the caller. */
2031static void surface_remove_pbo(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
2032{
2033 if (surface->flags & SFLAG_DIBSECTION)
2034 {
2035 surface->resource.allocatedMemory = surface->dib.bitmap_data;
2036 }
2037 else
2038 {
2039 if (!surface->resource.heapMemory)
2040 surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), 0, surface->resource.size + RESOURCE_ALIGNMENT);
2041 else if (!(surface->flags & SFLAG_CLIENT))
2042 ERR("Surface %p has heapMemory %p and flags %#x.\n",
2043 surface, surface->resource.heapMemory, surface->flags);
2044
2045 surface->resource.allocatedMemory = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory
2046 + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
2047 }
2048
2049 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
2050 checkGLcall("glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, surface->pbo)");
2051 GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0,
2052 surface->resource.size, surface->resource.allocatedMemory));
2053 checkGLcall("glGetBufferSubDataARB");
2054 GL_EXTCALL(glDeleteBuffersARB(1, &surface->pbo));
2055 checkGLcall("glDeleteBuffersARB");
2056
2057 surface->pbo = 0;
2058 surface->flags &= ~SFLAG_PBO;
2059}
2060
2061static BOOL surface_init_sysmem(struct wined3d_surface *surface)
2062{
2063 if (!surface->resource.allocatedMemory)
2064 {
2065 if (!surface->resource.heapMemory)
2066 {
2067 if (!(surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2068 surface->resource.size + RESOURCE_ALIGNMENT)))
2069 {
2070 ERR("Failed to allocate memory.\n");
2071 return FALSE;
2072 }
2073 }
2074 else if (!(surface->flags & SFLAG_CLIENT))
2075 {
2076 ERR("Surface %p has heapMemory %p and flags %#x.\n",
2077 surface, surface->resource.heapMemory, surface->flags);
2078 }
2079
2080 surface->resource.allocatedMemory =
2081 (BYTE *)(((ULONG_PTR)surface->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
2082 }
2083 else
2084 {
2085 memset(surface->resource.allocatedMemory, 0, surface->resource.size);
2086 }
2087
2088 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
2089
2090 return TRUE;
2091}
2092
2093/* Do not call while under the GL lock. */
2094static void surface_unload(struct wined3d_resource *resource)
2095{
2096 struct wined3d_surface *surface = surface_from_resource(resource);
2097 struct wined3d_renderbuffer_entry *entry, *entry2;
2098 struct wined3d_device *device = resource->device;
2099 const struct wined3d_gl_info *gl_info;
2100 struct wined3d_context *context;
2101
2102 TRACE("surface %p.\n", surface);
2103
2104 if (resource->pool == WINED3D_POOL_DEFAULT)
2105 {
2106 /* Default pool resources are supposed to be destroyed before Reset is called.
2107 * Implicit resources stay however. So this means we have an implicit render target
2108 * or depth stencil. The content may be destroyed, but we still have to tear down
2109 * opengl resources, so we cannot leave early.
2110 *
2111 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
2112 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
2113 * or the depth stencil into an FBO the texture or render buffer will be removed
2114 * and all flags get lost
2115 */
2116 if (!(surface->flags & SFLAG_PBO))
2117 surface_init_sysmem(surface);
2118 /* We also get here when the ddraw swapchain is destroyed, for example
2119 * for a mode switch. In this case this surface won't necessarily be
2120 * an implicit surface. We have to mark it lost so that the
2121 * application can restore it after the mode switch. */
2122 surface->flags |= SFLAG_LOST;
2123 }
2124 else
2125 {
2126 /* Load the surface into system memory */
2127 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
2128 surface_modify_location(surface, surface->draw_binding, FALSE);
2129 }
2130 surface_modify_location(surface, SFLAG_INTEXTURE, FALSE);
2131 surface_modify_location(surface, SFLAG_INSRGBTEX, FALSE);
2132 surface->flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
2133
2134 context = context_acquire(device, NULL);
2135 gl_info = context->gl_info;
2136
2137 /* Destroy PBOs, but load them into real sysmem before */
2138 if (surface->flags & SFLAG_PBO)
2139 surface_remove_pbo(surface, gl_info);
2140
2141 /* Destroy fbo render buffers. This is needed for implicit render targets, for
2142 * all application-created targets the application has to release the surface
2143 * before calling _Reset
2144 */
2145 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
2146 {
2147 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
2148 list_remove(&entry->entry);
2149 HeapFree(GetProcessHeap(), 0, entry);
2150 }
2151 list_init(&surface->renderbuffers);
2152 surface->current_renderbuffer = NULL;
2153
2154 /* If we're in a texture, the texture name belongs to the texture.
2155 * Otherwise, destroy it. */
2156 if (!surface->container)
2157 {
2158#ifdef VBOX_WITH_WINE_FIX_TEXCLEAR
2159 if (surface->texture_name)
2160#endif
2161 {
2162#ifdef VBOX_WITH_WDDM
2163 texture_gl_delete(surface->texture_name);
2164#else
2165 gl_info->gl_ops.gl.p_glDeleteTextures(1, &surface->texture_name);
2166#endif
2167 surface->texture_name = 0;
2168 }
2169#ifdef VBOX_WITH_WINE_FIX_TEXCLEAR
2170 if (surface->texture_name_srgb)
2171#endif
2172 {
2173#ifdef VBOX_WITH_WDDM
2174 texture_gl_delete(surface->texture_name_srgb);
2175#else
2176 gl_info->gl_ops.gl.p_glDeleteTextures(1, &surface->texture_name_srgb);
2177#endif
2178 surface->texture_name_srgb = 0;
2179 }
2180 }
2181 if (surface->rb_multisample)
2182 {
2183 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_multisample);
2184 surface->rb_multisample = 0;
2185 }
2186 if (surface->rb_resolved)
2187 {
2188 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_resolved);
2189 surface->rb_resolved = 0;
2190 }
2191
2192 context_release(context);
2193
2194 resource_unload(resource);
2195}
2196
2197static const struct wined3d_resource_ops surface_resource_ops =
2198{
2199 surface_unload,
2200};
2201
2202static const struct wined3d_surface_ops surface_ops =
2203{
2204 surface_private_setup,
2205 surface_realize_palette,
2206 surface_map,
2207 surface_unmap,
2208};
2209
2210/*****************************************************************************
2211 * Initializes the GDI surface, aka creates the DIB section we render to
2212 * The DIB section creation is done by calling GetDC, which will create the
2213 * section and releasing the dc to allow the app to use it. The dib section
2214 * will stay until the surface is released
2215 *
2216 * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
2217 * are set to the real sizes to save memory. The NONPOW2 flag is unset to
2218 * avoid confusion in the shared surface code.
2219 *
2220 * Returns:
2221 * WINED3D_OK on success
2222 * The return values of called methods on failure
2223 *
2224 *****************************************************************************/
2225static HRESULT gdi_surface_private_setup(struct wined3d_surface *surface)
2226{
2227 HRESULT hr;
2228
2229 TRACE("surface %p.\n", surface);
2230
2231 if (surface->resource.usage & WINED3DUSAGE_OVERLAY)
2232 {
2233 ERR("Overlays not yet supported by GDI surfaces.\n");
2234 return WINED3DERR_INVALIDCALL;
2235 }
2236
2237 /* Sysmem textures have memory already allocated - release it,
2238 * this avoids an unnecessary memcpy. */
2239 hr = surface_create_dib_section(surface);
2240 if (SUCCEEDED(hr))
2241 {
2242 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
2243 surface->resource.heapMemory = NULL;
2244 surface->resource.allocatedMemory = surface->dib.bitmap_data;
2245 }
2246
2247 /* We don't mind the nonpow2 stuff in GDI. */
2248 surface->pow2Width = surface->resource.width;
2249 surface->pow2Height = surface->resource.height;
2250
2251 return WINED3D_OK;
2252}
2253
2254static void gdi_surface_realize_palette(struct wined3d_surface *surface)
2255{
2256 struct wined3d_palette *palette = surface->palette;
2257
2258 TRACE("surface %p.\n", surface);
2259
2260 if (!palette) return;
2261
2262 if (surface->flags & SFLAG_DIBSECTION)
2263 {
2264 RGBQUAD col[256];
2265 unsigned int i;
2266
2267 TRACE("Updating the DC's palette.\n");
2268
2269 for (i = 0; i < 256; ++i)
2270 {
2271 col[i].rgbRed = palette->palents[i].peRed;
2272 col[i].rgbGreen = palette->palents[i].peGreen;
2273 col[i].rgbBlue = palette->palents[i].peBlue;
2274 col[i].rgbReserved = 0;
2275 }
2276 SetDIBColorTable(surface->hDC, 0, 256, col);
2277 }
2278
2279 /* Update the image because of the palette change. Some games like e.g.
2280 * Red Alert call SetEntries a lot to implement fading. */
2281 /* Tell the swapchain to update the screen. */
2282 if (surface->swapchain && surface == surface->swapchain->front_buffer)
2283 x11_copy_to_screen(surface->swapchain, NULL);
2284}
2285
2286static void gdi_surface_map(struct wined3d_surface *surface, const RECT *rect, DWORD flags)
2287{
2288 TRACE("surface %p, rect %s, flags %#x.\n",
2289 surface, wine_dbgstr_rect(rect), flags);
2290
2291 if (!(surface->flags & SFLAG_DIBSECTION))
2292 {
2293 HRESULT hr;
2294
2295 /* This happens on gdi surfaces if the application set a user pointer
2296 * and resets it. Recreate the DIB section. */
2297 if (FAILED(hr = surface_create_dib_section(surface)))
2298 {
2299 ERR("Failed to create dib section, hr %#x.\n", hr);
2300 return;
2301 }
2302 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
2303 surface->resource.heapMemory = NULL;
2304 surface->resource.allocatedMemory = surface->dib.bitmap_data;
2305 }
2306}
2307
2308static void gdi_surface_unmap(struct wined3d_surface *surface)
2309{
2310 TRACE("surface %p.\n", surface);
2311
2312 /* Tell the swapchain to update the screen. */
2313 if (surface->swapchain && surface == surface->swapchain->front_buffer)
2314 x11_copy_to_screen(surface->swapchain, &surface->lockedRect);
2315
2316 memset(&surface->lockedRect, 0, sizeof(RECT));
2317}
2318
2319static const struct wined3d_surface_ops gdi_surface_ops =
2320{
2321 gdi_surface_private_setup,
2322 gdi_surface_realize_palette,
2323 gdi_surface_map,
2324 gdi_surface_unmap,
2325};
2326
2327void surface_set_texture_name(struct wined3d_surface *surface, GLuint new_name, BOOL srgb)
2328{
2329 GLuint *name;
2330 DWORD flag;
2331
2332 TRACE("surface %p, new_name %u, srgb %#x.\n", surface, new_name, srgb);
2333
2334 if(srgb)
2335 {
2336 name = &surface->texture_name_srgb;
2337 flag = SFLAG_INSRGBTEX;
2338 }
2339 else
2340 {
2341 name = &surface->texture_name;
2342 flag = SFLAG_INTEXTURE;
2343 }
2344
2345 if (!*name && new_name)
2346 {
2347 /* FIXME: We shouldn't need to remove SFLAG_INTEXTURE if the
2348 * surface has no texture name yet. See if we can get rid of this. */
2349 if (surface->flags & flag)
2350 {
2351 ERR("Surface has %s set, but no texture name.\n", debug_surflocation(flag));
2352#ifndef VBOX_WITH_WDDM
2353 surface_modify_location(surface, flag, FALSE);
2354#endif
2355 }
2356 }
2357
2358#ifdef VBOX_WITH_WDDM
2359 if (VBOXSHRC_IS_SHARED(surface))
2360 {
2361 Assert(VBOXSHRC_GET_SHAREHANDLE(surface) == NULL
2362 || (GLuint)VBOXSHRC_GET_SHAREHANDLE(surface) == new_name
2363 || new_name == 0 /* on cleanup */);
2364 VBOXSHRC_SET_SHAREHANDLE(surface, new_name);
2365 }
2366#endif
2367 *name = new_name;
2368 surface_force_reload(surface);
2369}
2370
2371void surface_set_texture_target(struct wined3d_surface *surface, GLenum target, GLint level)
2372{
2373 TRACE("surface %p, target %#x.\n", surface, target);
2374
2375 if (surface->texture_target != target)
2376 {
2377 if (target == GL_TEXTURE_RECTANGLE_ARB)
2378 {
2379 surface->flags &= ~SFLAG_NORMCOORD;
2380 }
2381 else if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
2382 {
2383 surface->flags |= SFLAG_NORMCOORD;
2384 }
2385 }
2386 surface->texture_target = target;
2387 surface->texture_level = level;
2388 surface_force_reload(surface);
2389}
2390
2391/* This call just downloads data, the caller is responsible for binding the
2392 * correct texture. */
2393/* Context activation is done by the caller. */
2394static void surface_download_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
2395{
2396 const struct wined3d_format *format = surface->resource.format;
2397
2398 /* Only support read back of converted P8 surfaces. */
2399 if (surface->flags & SFLAG_CONVERTED && format->id != WINED3DFMT_P8_UINT)
2400 {
2401 ERR("Trying to read back converted surface %p with format %s.\n", surface, debug_d3dformat(format->id));
2402 return;
2403 }
2404
2405 if (format->flags & WINED3DFMT_FLAG_COMPRESSED)
2406 {
2407 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
2408 surface, surface->texture_level, format->glFormat, format->glType,
2409 surface->resource.allocatedMemory);
2410
2411 if (surface->flags & SFLAG_PBO)
2412 {
2413 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
2414 checkGLcall("glBindBufferARB");
2415 GL_EXTCALL(glGetCompressedTexImageARB(surface->texture_target, surface->texture_level, NULL));
2416 checkGLcall("glGetCompressedTexImageARB");
2417 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
2418 checkGLcall("glBindBufferARB");
2419 }
2420 else
2421 {
2422 GL_EXTCALL(glGetCompressedTexImageARB(surface->texture_target,
2423 surface->texture_level, surface->resource.allocatedMemory));
2424 checkGLcall("glGetCompressedTexImageARB");
2425 }
2426
2427 }
2428 else
2429 {
2430 void *mem;
2431 GLenum gl_format = format->glFormat;
2432 GLenum gl_type = format->glType;
2433 int src_pitch = 0;
2434 int dst_pitch = 0;
2435
2436 /* In case of P8 the index is stored in the alpha component if the primary render target uses P8. */
2437 if (format->id == WINED3DFMT_P8_UINT && primary_render_target_is_p8(surface->resource.device))
2438 {
2439 gl_format = GL_ALPHA;
2440 gl_type = GL_UNSIGNED_BYTE;
2441 }
2442
2443 if (surface->flags & SFLAG_NONPOW2)
2444 {
2445 unsigned char alignment = surface->resource.device->surface_alignment;
2446 src_pitch = format->byte_count * surface->pow2Width;
2447 dst_pitch = wined3d_surface_get_pitch(surface);
2448 src_pitch = (src_pitch + alignment - 1) & ~(alignment - 1);
2449 mem = HeapAlloc(GetProcessHeap(), 0, src_pitch * surface->pow2Height);
2450 }
2451 else
2452 {
2453 mem = surface->resource.allocatedMemory;
2454 }
2455
2456 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
2457 surface, surface->texture_level, gl_format, gl_type, mem);
2458
2459 if (surface->flags & SFLAG_PBO)
2460 {
2461 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
2462 checkGLcall("glBindBufferARB");
2463
2464 gl_info->gl_ops.gl.p_glGetTexImage(surface->texture_target, surface->texture_level,
2465 gl_format, gl_type, NULL);
2466 checkGLcall("glGetTexImage");
2467
2468 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
2469 checkGLcall("glBindBufferARB");
2470 }
2471 else
2472 {
2473 gl_info->gl_ops.gl.p_glGetTexImage(surface->texture_target, surface->texture_level,
2474 gl_format, gl_type, mem);
2475 checkGLcall("glGetTexImage");
2476 }
2477
2478 if (surface->flags & SFLAG_NONPOW2)
2479 {
2480 const BYTE *src_data;
2481 BYTE *dst_data;
2482 UINT y;
2483 /*
2484 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
2485 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
2486 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
2487 *
2488 * We're doing this...
2489 *
2490 * instead of boxing the texture :
2491 * |<-texture width ->| -->pow2width| /\
2492 * |111111111111111111| | |
2493 * |222 Texture 222222| boxed empty | texture height
2494 * |3333 Data 33333333| | |
2495 * |444444444444444444| | \/
2496 * ----------------------------------- |
2497 * | boxed empty | boxed empty | pow2height
2498 * | | | \/
2499 * -----------------------------------
2500 *
2501 *
2502 * we're repacking the data to the expected texture width
2503 *
2504 * |<-texture width ->| -->pow2width| /\
2505 * |111111111111111111222222222222222| |
2506 * |222333333333333333333444444444444| texture height
2507 * |444444 | |
2508 * | | \/
2509 * | | |
2510 * | empty | pow2height
2511 * | | \/
2512 * -----------------------------------
2513 *
2514 * == is the same as
2515 *
2516 * |<-texture width ->| /\
2517 * |111111111111111111|
2518 * |222222222222222222|texture height
2519 * |333333333333333333|
2520 * |444444444444444444| \/
2521 * --------------------
2522 *
2523 * this also means that any references to allocatedMemory should work with the data as if were a
2524 * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
2525 *
2526 * internally the texture is still stored in a boxed format so any references to textureName will
2527 * get a boxed texture with width pow2width and not a texture of width resource.width.
2528 *
2529 * Performance should not be an issue, because applications normally do not lock the surfaces when
2530 * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
2531 * and doesn't have to be re-read. */
2532 src_data = mem;
2533 dst_data = surface->resource.allocatedMemory;
2534 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", surface, src_pitch, dst_pitch);
2535 for (y = 0; y < surface->resource.height; ++y)
2536 {
2537 memcpy(dst_data, src_data, dst_pitch);
2538 src_data += src_pitch;
2539 dst_data += dst_pitch;
2540 }
2541
2542 HeapFree(GetProcessHeap(), 0, mem);
2543 }
2544 }
2545
2546 /* Surface has now been downloaded */
2547 surface->flags |= SFLAG_INSYSMEM;
2548}
2549
2550/* This call just uploads data, the caller is responsible for binding the
2551 * correct texture. */
2552/* Context activation is done by the caller. */
2553static void surface_upload_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
2554 const struct wined3d_format *format, const RECT *src_rect, UINT src_pitch, const POINT *dst_point,
2555 BOOL srgb, const struct wined3d_bo_address *data)
2556{
2557 UINT update_w = src_rect->right - src_rect->left;
2558 UINT update_h = src_rect->bottom - src_rect->top;
2559
2560 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n",
2561 surface, gl_info, debug_d3dformat(format->id), wine_dbgstr_rect(src_rect), src_pitch,
2562 wine_dbgstr_point(dst_point), srgb, data->buffer_object, data->addr);
2563
2564 if (surface->resource.map_count)
2565 {
2566 WARN("Uploading a surface that is currently mapped, setting SFLAG_PIN_SYSMEM.\n");
2567 surface->flags |= SFLAG_PIN_SYSMEM;
2568 }
2569
2570 if (format->flags & WINED3DFMT_FLAG_HEIGHT_SCALE)
2571 {
2572 update_h *= format->height_scale.numerator;
2573 update_h /= format->height_scale.denominator;
2574 }
2575
2576 if (data->buffer_object)
2577 {
2578 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, data->buffer_object));
2579 checkGLcall("glBindBufferARB");
2580 }
2581
2582 if (format->flags & WINED3DFMT_FLAG_COMPRESSED)
2583 {
2584 UINT row_length = wined3d_format_calculate_size(format, 1, update_w, 1);
2585 UINT row_count = (update_h + format->block_height - 1) / format->block_height;
2586 const BYTE *addr = data->addr;
2587 GLenum internal;
2588
2589 addr += (src_rect->top / format->block_height) * src_pitch;
2590 addr += (src_rect->left / format->block_width) * format->block_byte_count;
2591
2592 if (srgb)
2593 internal = format->glGammaInternal;
2594 else if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(surface))
2595 internal = format->rtInternal;
2596 else
2597 internal = format->glInternal;
2598
2599 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
2600 "format %#x, image_size %#x, addr %p.\n", surface->texture_target, surface->texture_level,
2601 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr);
2602
2603 if (row_length == src_pitch)
2604 {
2605 GL_EXTCALL(glCompressedTexSubImage2DARB(surface->texture_target, surface->texture_level,
2606 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr));
2607 }
2608 else
2609 {
2610 UINT row, y;
2611
2612 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
2613 * can't use the unpack row length like below. */
2614 for (row = 0, y = dst_point->y; row < row_count; ++row)
2615 {
2616 GL_EXTCALL(glCompressedTexSubImage2DARB(surface->texture_target, surface->texture_level,
2617 dst_point->x, y, update_w, format->block_height, internal, row_length, addr));
2618 y += format->block_height;
2619 addr += src_pitch;
2620 }
2621 }
2622 checkGLcall("glCompressedTexSubImage2DARB");
2623 }
2624 else
2625 {
2626 const BYTE *addr = data->addr;
2627
2628 addr += src_rect->top * src_pitch;
2629 addr += src_rect->left * format->byte_count;
2630
2631 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n",
2632 surface->texture_target, surface->texture_level, dst_point->x, dst_point->y,
2633 update_w, update_h, format->glFormat, format->glType, addr);
2634
2635 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, src_pitch / format->byte_count);
2636 gl_info->gl_ops.gl.p_glTexSubImage2D(surface->texture_target, surface->texture_level,
2637 dst_point->x, dst_point->y, update_w, update_h, format->glFormat, format->glType, addr);
2638 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
2639 checkGLcall("glTexSubImage2D");
2640 }
2641
2642 if (data->buffer_object)
2643 {
2644 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
2645 checkGLcall("glBindBufferARB");
2646 }
2647
2648 if (wined3d_settings.strict_draw_ordering)
2649 gl_info->gl_ops.gl.p_glFlush();
2650
2651 if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
2652 {
2653 struct wined3d_device *device = surface->resource.device;
2654 unsigned int i;
2655
2656 for (i = 0; i < device->context_count; ++i)
2657 {
2658 context_surface_update(device->contexts[i], surface);
2659 }
2660 }
2661}
2662
2663static HRESULT d3dfmt_get_conv(const struct wined3d_surface *surface, BOOL need_alpha_ck, BOOL use_texturing,
2664 struct wined3d_format *format, enum wined3d_conversion_type *conversion_type)
2665{
2666 BOOL colorkey_active = need_alpha_ck && (surface->CKeyFlags & WINEDDSD_CKSRCBLT);
2667 const struct wined3d_device *device = surface->resource.device;
2668 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
2669 BOOL blit_supported = FALSE;
2670
2671 /* Copy the default values from the surface. Below we might perform fixups */
2672 /* TODO: get rid of color keying desc fixups by using e.g. a table. */
2673 *format = *surface->resource.format;
2674 *conversion_type = WINED3D_CT_NONE;
2675
2676 /* Ok, now look if we have to do any conversion */
2677 switch (surface->resource.format->id)
2678 {
2679 case WINED3DFMT_P8_UINT:
2680 /* Below the call to blit_supported is disabled for Wine 1.2
2681 * because the function isn't operating correctly yet. At the
2682 * moment 8-bit blits are handled in software and if certain GL
2683 * extensions are around, surface conversion is performed at
2684 * upload time. The blit_supported call recognizes it as a
2685 * destination fixup. This type of upload 'fixup' and 8-bit to
2686 * 8-bit blits need to be handled by the blit_shader.
2687 * TODO: get rid of this #if 0. */
2688#if 0
2689 blit_supported = device->blitter->blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
2690 &rect, surface->resource.usage, surface->resource.pool, surface->resource.format,
2691 &rect, surface->resource.usage, surface->resource.pool, surface->resource.format);
2692#endif
2693 blit_supported = gl_info->supported[EXT_PALETTED_TEXTURE] || gl_info->supported[ARB_FRAGMENT_PROGRAM];
2694
2695 /* Use conversion when the blit_shader backend supports it. It only supports this in case of
2696 * texturing. Further also use conversion in case of color keying.
2697 * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
2698 * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
2699 * conflicts with this.
2700 */
2701 if (!((blit_supported && device->fb.render_targets && surface == device->fb.render_targets[0]))
2702 || colorkey_active || !use_texturing)
2703 {
2704 format->glFormat = GL_RGBA;
2705 format->glInternal = GL_RGBA;
2706 format->glType = GL_UNSIGNED_BYTE;
2707 format->conv_byte_count = 4;
2708 if (colorkey_active)
2709 *conversion_type = WINED3D_CT_PALETTED_CK;
2710 else
2711 *conversion_type = WINED3D_CT_PALETTED;
2712 }
2713 break;
2714
2715 case WINED3DFMT_B2G3R3_UNORM:
2716 /* **********************
2717 GL_UNSIGNED_BYTE_3_3_2
2718 ********************** */
2719 if (colorkey_active) {
2720 /* This texture format will never be used.. So do not care about color keying
2721 up until the point in time it will be needed :-) */
2722 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
2723 }
2724 break;
2725
2726 case WINED3DFMT_B5G6R5_UNORM:
2727 if (colorkey_active)
2728 {
2729 *conversion_type = WINED3D_CT_CK_565;
2730 format->glFormat = GL_RGBA;
2731 format->glInternal = GL_RGB5_A1;
2732 format->glType = GL_UNSIGNED_SHORT_5_5_5_1;
2733 format->conv_byte_count = 2;
2734 }
2735 break;
2736
2737 case WINED3DFMT_B5G5R5X1_UNORM:
2738 if (colorkey_active)
2739 {
2740 *conversion_type = WINED3D_CT_CK_5551;
2741 format->glFormat = GL_BGRA;
2742 format->glInternal = GL_RGB5_A1;
2743 format->glType = GL_UNSIGNED_SHORT_1_5_5_5_REV;
2744 format->conv_byte_count = 2;
2745 }
2746 break;
2747
2748 case WINED3DFMT_B8G8R8_UNORM:
2749 if (colorkey_active)
2750 {
2751 *conversion_type = WINED3D_CT_CK_RGB24;
2752 format->glFormat = GL_RGBA;
2753 format->glInternal = GL_RGBA8;
2754 format->glType = GL_UNSIGNED_INT_8_8_8_8;
2755 format->conv_byte_count = 4;
2756 }
2757 break;
2758
2759 case WINED3DFMT_B8G8R8X8_UNORM:
2760 if (colorkey_active)
2761 {
2762 *conversion_type = WINED3D_CT_RGB32_888;
2763 format->glFormat = GL_RGBA;
2764 format->glInternal = GL_RGBA8;
2765 format->glType = GL_UNSIGNED_INT_8_8_8_8;
2766 format->conv_byte_count = 4;
2767 }
2768 break;
2769
2770 case WINED3DFMT_B8G8R8A8_UNORM:
2771 if (colorkey_active)
2772 {
2773 *conversion_type = WINED3D_CT_CK_ARGB32;
2774 format->conv_byte_count = 4;
2775 }
2776 break;
2777
2778 default:
2779 break;
2780 }
2781
2782 if (*conversion_type != WINED3D_CT_NONE)
2783 {
2784 format->rtInternal = format->glInternal;
2785 format->glGammaInternal = format->glInternal;
2786 }
2787
2788 return WINED3D_OK;
2789}
2790
2791static BOOL surface_check_block_align(struct wined3d_surface *surface, const RECT *rect)
2792{
2793 UINT width_mask, height_mask;
2794
2795 if (!rect->left && !rect->top
2796 && rect->right == surface->resource.width
2797 && rect->bottom == surface->resource.height)
2798 return TRUE;
2799
2800 /* This assumes power of two block sizes, but NPOT block sizes would be
2801 * silly anyway. */
2802 width_mask = surface->resource.format->block_width - 1;
2803 height_mask = surface->resource.format->block_height - 1;
2804
2805 if (!(rect->left & width_mask) && !(rect->top & height_mask)
2806 && !(rect->right & width_mask) && !(rect->bottom & height_mask))
2807 return TRUE;
2808
2809 return FALSE;
2810}
2811
2812HRESULT surface_upload_from_surface(struct wined3d_surface *dst_surface, const POINT *dst_point,
2813 struct wined3d_surface *src_surface, const RECT *src_rect)
2814{
2815 const struct wined3d_format *src_format;
2816 const struct wined3d_format *dst_format;
2817 const struct wined3d_gl_info *gl_info;
2818 enum wined3d_conversion_type convert;
2819 struct wined3d_context *context;
2820 struct wined3d_bo_address data;
2821 struct wined3d_format format;
2822 UINT update_w, update_h;
2823 UINT dst_w, dst_h;
2824 RECT r, dst_rect;
2825 UINT src_pitch;
2826 POINT p;
2827
2828 TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
2829 dst_surface, wine_dbgstr_point(dst_point),
2830 src_surface, wine_dbgstr_rect(src_rect));
2831
2832 src_format = src_surface->resource.format;
2833 dst_format = dst_surface->resource.format;
2834
2835 if (src_format->id != dst_format->id)
2836 {
2837 WARN("Source and destination surfaces should have the same format.\n");
2838 return WINED3DERR_INVALIDCALL;
2839 }
2840
2841 if (!dst_point)
2842 {
2843 p.x = 0;
2844 p.y = 0;
2845 dst_point = &p;
2846 }
2847 else if (dst_point->x < 0 || dst_point->y < 0)
2848 {
2849 WARN("Invalid destination point.\n");
2850 return WINED3DERR_INVALIDCALL;
2851 }
2852
2853 if (!src_rect)
2854 {
2855 r.left = 0;
2856 r.top = 0;
2857 r.right = src_surface->resource.width;
2858 r.bottom = src_surface->resource.height;
2859 src_rect = &r;
2860 }
2861 else if (src_rect->left < 0 || src_rect->left >= src_rect->right
2862 || src_rect->top < 0 || src_rect->top >= src_rect->bottom)
2863 {
2864 WARN("Invalid source rectangle.\n");
2865 return WINED3DERR_INVALIDCALL;
2866 }
2867
2868 dst_w = dst_surface->resource.width;
2869 dst_h = dst_surface->resource.height;
2870
2871 update_w = src_rect->right - src_rect->left;
2872 update_h = src_rect->bottom - src_rect->top;
2873
2874 if (update_w > dst_w || dst_point->x > dst_w - update_w
2875 || update_h > dst_h || dst_point->y > dst_h - update_h)
2876 {
2877 WARN("Destination out of bounds.\n");
2878 return WINED3DERR_INVALIDCALL;
2879 }
2880
2881 if ((src_format->flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align(src_surface, src_rect))
2882 {
2883 WARN("Source rectangle not block-aligned.\n");
2884 return WINED3DERR_INVALIDCALL;
2885 }
2886
2887 SetRect(&dst_rect, dst_point->x, dst_point->y, dst_point->x + update_w, dst_point->y + update_h);
2888 if ((dst_format->flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align(dst_surface, &dst_rect))
2889 {
2890 WARN("Destination rectangle not block-aligned.\n");
2891 return WINED3DERR_INVALIDCALL;
2892 }
2893
2894 /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
2895 d3dfmt_get_conv(dst_surface, FALSE, TRUE, &format, &convert);
2896 if (convert != WINED3D_CT_NONE || format.convert)
2897 return wined3d_surface_blt(dst_surface, &dst_rect, src_surface, src_rect, 0, NULL, WINED3D_TEXF_POINT);
2898
2899 context = context_acquire(dst_surface->resource.device, NULL);
2900 gl_info = context->gl_info;
2901
2902 /* Only load the surface for partial updates. For newly allocated texture
2903 * the texture wouldn't be the current location, and we'd upload zeroes
2904 * just to overwrite them again. */
2905 if (update_w == dst_w && update_h == dst_h)
2906 surface_prepare_texture(dst_surface, context, FALSE);
2907 else
2908 surface_load_location(dst_surface, SFLAG_INTEXTURE, NULL);
2909 surface_bind(dst_surface, context, FALSE);
2910
2911 data.buffer_object = src_surface->pbo;
2912 data.addr = src_surface->resource.allocatedMemory;
2913 src_pitch = wined3d_surface_get_pitch(src_surface);
2914
2915 surface_upload_data(dst_surface, gl_info, src_format, src_rect, src_pitch, dst_point, FALSE, &data);
2916
2917 invalidate_active_texture(dst_surface->resource.device, context);
2918
2919 context_release(context);
2920
2921 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
2922 return WINED3D_OK;
2923}
2924
2925/* This call just allocates the texture, the caller is responsible for binding
2926 * the correct texture. */
2927/* Context activation is done by the caller. */
2928static void surface_allocate_surface(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
2929 const struct wined3d_format *format, BOOL srgb)
2930{
2931 BOOL enable_client_storage = FALSE;
2932 GLsizei width = surface->pow2Width;
2933 GLsizei height = surface->pow2Height;
2934 const BYTE *mem = NULL;
2935 GLenum internal;
2936
2937#ifdef VBOX_WITH_WDDM
2938 if (VBOXSHRC_IS_SHARED_OPENED(surface))
2939 {
2940 ERR("trying to allocate shared openned resource!!, ignoring..\n");
2941 return;
2942 }
2943#endif
2944
2945 if (srgb)
2946 {
2947 internal = format->glGammaInternal;
2948 }
2949 else if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(surface))
2950 {
2951 internal = format->rtInternal;
2952 }
2953 else
2954 {
2955 internal = format->glInternal;
2956 }
2957
2958 if (!internal)
2959 FIXME("No GL internal format for format %s.\n", debug_d3dformat(format->id));
2960
2961 if (format->flags & WINED3DFMT_FLAG_HEIGHT_SCALE)
2962 {
2963 height *= format->height_scale.numerator;
2964 height /= format->height_scale.denominator;
2965 }
2966
2967 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",
2968 surface, surface->texture_target, surface->texture_level, debug_d3dformat(format->id),
2969 internal, width, height, format->glFormat, format->glType);
2970
2971 if (gl_info->supported[APPLE_CLIENT_STORAGE])
2972 {
2973 if (surface->flags & (SFLAG_NONPOW2 | SFLAG_DIBSECTION | SFLAG_CONVERTED)
2974 || !surface->resource.allocatedMemory)
2975 {
2976 /* In some cases we want to disable client storage.
2977 * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
2978 * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
2979 * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
2980 * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively
2981 */
2982 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2983 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2984 surface->flags &= ~SFLAG_CLIENT;
2985 enable_client_storage = TRUE;
2986 }
2987 else
2988 {
2989 surface->flags |= SFLAG_CLIENT;
2990
2991 /* Point OpenGL to our allocated texture memory. Do not use
2992 * resource.allocatedMemory here because it might point into a
2993 * PBO. Instead use heapMemory, but get the alignment right. */
2994 mem = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory
2995 + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
2996 }
2997 }
2998
2999 if (format->flags & WINED3DFMT_FLAG_COMPRESSED && mem)
3000 {
3001 GL_EXTCALL(glCompressedTexImage2DARB(surface->texture_target, surface->texture_level,
3002 internal, width, height, 0, surface->resource.size, mem));
3003 checkGLcall("glCompressedTexImage2DARB");
3004 }
3005 else
3006 {
3007 gl_info->gl_ops.gl.p_glTexImage2D(surface->texture_target, surface->texture_level,
3008 internal, width, height, 0, format->glFormat, format->glType, mem);
3009 checkGLcall("glTexImage2D");
3010 }
3011
3012 if (enable_client_storage)
3013 {
3014 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
3015 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
3016 }
3017}
3018
3019/* In D3D the depth stencil dimensions have to be greater than or equal to the
3020 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
3021/* TODO: We should synchronize the renderbuffer's content with the texture's content. */
3022/* Context activation is done by the caller. */
3023void surface_set_compatible_renderbuffer(struct wined3d_surface *surface, const struct wined3d_surface *rt)
3024{
3025 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
3026 struct wined3d_renderbuffer_entry *entry;
3027 GLuint renderbuffer = 0;
3028 unsigned int src_width, src_height;
3029 unsigned int width, height;
3030
3031 if (rt && rt->resource.format->id != WINED3DFMT_NULL)
3032 {
3033 width = rt->pow2Width;
3034 height = rt->pow2Height;
3035 }
3036 else
3037 {
3038 width = surface->pow2Width;
3039 height = surface->pow2Height;
3040 }
3041
3042 src_width = surface->pow2Width;
3043 src_height = surface->pow2Height;
3044
3045 /* A depth stencil smaller than the render target is not valid */
3046 if (width > src_width || height > src_height) return;
3047
3048 /* Remove any renderbuffer set if the sizes match */
3049 if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]
3050 || (width == src_width && height == src_height))
3051 {
3052 surface->current_renderbuffer = NULL;
3053 return;
3054 }
3055
3056 /* Look if we've already got a renderbuffer of the correct dimensions */
3057 LIST_FOR_EACH_ENTRY(entry, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
3058 {
3059 if (entry->width == width && entry->height == height)
3060 {
3061 renderbuffer = entry->id;
3062 surface->current_renderbuffer = entry;
3063 break;
3064 }
3065 }
3066
3067 if (!renderbuffer)
3068 {
3069 gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
3070 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
3071 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER,
3072 surface->resource.format->glInternal, width, height);
3073
3074 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
3075 entry->width = width;
3076 entry->height = height;
3077 entry->id = renderbuffer;
3078 list_add_head(&surface->renderbuffers, &entry->entry);
3079
3080 surface->current_renderbuffer = entry;
3081 }
3082
3083 checkGLcall("set_compatible_renderbuffer");
3084}
3085
3086GLenum surface_get_gl_buffer(const struct wined3d_surface *surface)
3087{
3088 const struct wined3d_swapchain *swapchain = surface->swapchain;
3089
3090 TRACE("surface %p.\n", surface);
3091
3092 if (!swapchain)
3093 {
3094 ERR("Surface %p is not on a swapchain.\n", surface);
3095 return GL_NONE;
3096 }
3097
3098 if (swapchain->back_buffers && swapchain->back_buffers[0] == surface)
3099 {
3100 if (swapchain->render_to_fbo)
3101 {
3102 TRACE("Returning GL_COLOR_ATTACHMENT0\n");
3103 return GL_COLOR_ATTACHMENT0;
3104 }
3105 TRACE("Returning GL_BACK\n");
3106 return GL_BACK;
3107 }
3108 else if (surface == swapchain->front_buffer)
3109 {
3110 TRACE("Returning GL_FRONT\n");
3111 return GL_FRONT;
3112 }
3113
3114 FIXME("Higher back buffer, returning GL_BACK\n");
3115 return GL_BACK;
3116}
3117
3118/* Slightly inefficient way to handle multiple dirty rects but it works :) */
3119void surface_add_dirty_rect(struct wined3d_surface *surface, const struct wined3d_box *dirty_rect)
3120{
3121 TRACE("surface %p, dirty_rect %p.\n", surface, dirty_rect);
3122
3123 if (!(surface->flags & SFLAG_INSYSMEM) && (surface->flags & SFLAG_INTEXTURE))
3124 /* No partial locking for textures yet. */
3125 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
3126
3127 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
3128 if (dirty_rect)
3129 {
3130 surface->dirtyRect.left = min(surface->dirtyRect.left, dirty_rect->left);
3131 surface->dirtyRect.top = min(surface->dirtyRect.top, dirty_rect->top);
3132 surface->dirtyRect.right = max(surface->dirtyRect.right, dirty_rect->right);
3133 surface->dirtyRect.bottom = max(surface->dirtyRect.bottom, dirty_rect->bottom);
3134 }
3135 else
3136 {
3137 surface->dirtyRect.left = 0;
3138 surface->dirtyRect.top = 0;
3139 surface->dirtyRect.right = surface->resource.width;
3140 surface->dirtyRect.bottom = surface->resource.height;
3141 }
3142
3143 /* if the container is a texture then mark it dirty. */
3144 if (surface->container)
3145 {
3146 TRACE("Passing to container.\n");
3147 wined3d_texture_set_dirty(surface->container, TRUE);
3148 }
3149}
3150
3151HRESULT surface_load(struct wined3d_surface *surface, BOOL srgb)
3152{
3153 DWORD flag = srgb ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
3154 BOOL ck_changed;
3155
3156 TRACE("surface %p, srgb %#x.\n", surface, srgb);
3157
3158 if (surface->resource.pool == WINED3D_POOL_SCRATCH)
3159 {
3160 ERR("Not supported on scratch surfaces.\n");
3161 return WINED3DERR_INVALIDCALL;
3162 }
3163
3164 ck_changed = !(surface->flags & SFLAG_GLCKEY) != !(surface->CKeyFlags & WINEDDSD_CKSRCBLT);
3165
3166 /* Reload if either the texture and sysmem have different ideas about the
3167 * color key, or the actual key values changed. */
3168 if (ck_changed || ((surface->CKeyFlags & WINEDDSD_CKSRCBLT)
3169 && (surface->gl_color_key.color_space_low_value != surface->src_blt_color_key.color_space_low_value
3170 || surface->gl_color_key.color_space_high_value != surface->src_blt_color_key.color_space_high_value)))
3171 {
3172 TRACE("Reloading because of color keying\n");
3173 /* To perform the color key conversion we need a sysmem copy of
3174 * the surface. Make sure we have it. */
3175
3176 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
3177 /* Make sure the texture is reloaded because of the color key change,
3178 * this kills performance though :( */
3179 /* TODO: This is not necessarily needed with hw palettized texture support. */
3180 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
3181 /* Switching color keying on / off may change the internal format. */
3182 if (ck_changed)
3183 surface_force_reload(surface);
3184 }
3185 else if (!(surface->flags & flag))
3186 {
3187 TRACE("Reloading because surface is dirty.\n");
3188 }
3189 else
3190 {
3191 TRACE("surface is already in texture\n");
3192 return WINED3D_OK;
3193 }
3194
3195 /* No partial locking for textures yet. */
3196 surface_load_location(surface, flag, NULL);
3197 surface_evict_sysmem(surface);
3198
3199 return WINED3D_OK;
3200}
3201
3202/* See also float_16_to_32() in wined3d_private.h */
3203static inline unsigned short float_32_to_16(const float *in)
3204{
3205 int exp = 0;
3206 float tmp = fabsf(*in);
3207 unsigned int mantissa;
3208 unsigned short ret;
3209
3210 /* Deal with special numbers */
3211 if (*in == 0.0f)
3212 return 0x0000;
3213 if (isnan(*in))
3214 return 0x7c01;
3215 if (isinf(*in))
3216 return (*in < 0.0f ? 0xfc00 : 0x7c00);
3217
3218 if (tmp < powf(2, 10))
3219 {
3220 do
3221 {
3222 tmp = tmp * 2.0f;
3223 exp--;
3224 } while (tmp < powf(2, 10));
3225 }
3226 else if (tmp >= powf(2, 11))
3227 {
3228 do
3229 {
3230 tmp /= 2.0f;
3231 exp++;
3232 } while (tmp >= powf(2, 11));
3233 }
3234
3235 mantissa = (unsigned int)tmp;
3236 if (tmp - mantissa >= 0.5f)
3237 ++mantissa; /* Round to nearest, away from zero. */
3238
3239 exp += 10; /* Normalize the mantissa. */
3240 exp += 15; /* Exponent is encoded with excess 15. */
3241
3242 if (exp > 30) /* too big */
3243 {
3244 ret = 0x7c00; /* INF */
3245 }
3246 else if (exp <= 0)
3247 {
3248 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
3249 while (exp <= 0)
3250 {
3251 mantissa = mantissa >> 1;
3252 ++exp;
3253 }
3254 ret = mantissa & 0x3ff;
3255 }
3256 else
3257 {
3258 ret = (exp << 10) | (mantissa & 0x3ff);
3259 }
3260
3261 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
3262 return ret;
3263}
3264
3265ULONG CDECL wined3d_surface_incref(struct wined3d_surface *surface)
3266{
3267 ULONG refcount;
3268
3269 TRACE("surface %p, swapchain %p, container %p.\n",
3270 surface, surface->swapchain, surface->container);
3271
3272 if (surface->swapchain)
3273 return wined3d_swapchain_incref(surface->swapchain);
3274
3275 if (surface->container)
3276 return wined3d_texture_incref(surface->container);
3277
3278 refcount = InterlockedIncrement(&surface->resource.ref);
3279 TRACE("%p increasing refcount to %u.\n", surface, refcount);
3280
3281 return refcount;
3282}
3283
3284/* Do not call while under the GL lock. */
3285ULONG CDECL wined3d_surface_decref(struct wined3d_surface *surface)
3286{
3287 ULONG refcount;
3288
3289 TRACE("surface %p, swapchain %p, container %p.\n",
3290 surface, surface->swapchain, surface->container);
3291
3292 if (surface->swapchain)
3293 return wined3d_swapchain_decref(surface->swapchain);
3294
3295 if (surface->container)
3296 return wined3d_texture_decref(surface->container);
3297
3298 refcount = InterlockedDecrement(&surface->resource.ref);
3299 TRACE("%p decreasing refcount to %u.\n", surface, refcount);
3300
3301 if (!refcount)
3302 {
3303 surface_cleanup(surface);
3304 surface->resource.parent_ops->wined3d_object_destroyed(surface->resource.parent);
3305
3306 TRACE("Destroyed surface %p.\n", surface);
3307 HeapFree(GetProcessHeap(), 0, surface);
3308 }
3309
3310 return refcount;
3311}
3312
3313DWORD CDECL wined3d_surface_set_priority(struct wined3d_surface *surface, DWORD priority)
3314{
3315 return resource_set_priority(&surface->resource, priority);
3316}
3317
3318DWORD CDECL wined3d_surface_get_priority(const struct wined3d_surface *surface)
3319{
3320 return resource_get_priority(&surface->resource);
3321}
3322
3323void CDECL wined3d_surface_preload(struct wined3d_surface *surface)
3324{
3325 TRACE("surface %p.\n", surface);
3326
3327 if (!surface->resource.device->d3d_initialized)
3328 {
3329 ERR("D3D not initialized.\n");
3330 return;
3331 }
3332
3333 surface_internal_preload(surface, SRGB_ANY);
3334}
3335
3336void * CDECL wined3d_surface_get_parent(const struct wined3d_surface *surface)
3337{
3338 TRACE("surface %p.\n", surface);
3339
3340 return surface->resource.parent;
3341}
3342
3343struct wined3d_resource * CDECL wined3d_surface_get_resource(struct wined3d_surface *surface)
3344{
3345 TRACE("surface %p.\n", surface);
3346
3347 return &surface->resource;
3348}
3349
3350HRESULT CDECL wined3d_surface_get_blt_status(const struct wined3d_surface *surface, DWORD flags)
3351{
3352 TRACE("surface %p, flags %#x.\n", surface, flags);
3353
3354 switch (flags)
3355 {
3356 case WINEDDGBS_CANBLT:
3357 case WINEDDGBS_ISBLTDONE:
3358 return WINED3D_OK;
3359
3360 default:
3361 return WINED3DERR_INVALIDCALL;
3362 }
3363}
3364
3365HRESULT CDECL wined3d_surface_get_flip_status(const struct wined3d_surface *surface, DWORD flags)
3366{
3367 TRACE("surface %p, flags %#x.\n", surface, flags);
3368
3369 /* XXX: DDERR_INVALIDSURFACETYPE */
3370
3371 switch (flags)
3372 {
3373 case WINEDDGFS_CANFLIP:
3374 case WINEDDGFS_ISFLIPDONE:
3375 return WINED3D_OK;
3376
3377 default:
3378 return WINED3DERR_INVALIDCALL;
3379 }
3380}
3381
3382HRESULT CDECL wined3d_surface_is_lost(const struct wined3d_surface *surface)
3383{
3384 TRACE("surface %p.\n", surface);
3385
3386 /* D3D8 and 9 loose full devices, ddraw only surfaces. */
3387 return surface->flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
3388}
3389
3390HRESULT CDECL wined3d_surface_restore(struct wined3d_surface *surface)
3391{
3392 TRACE("surface %p.\n", surface);
3393
3394 surface->flags &= ~SFLAG_LOST;
3395 return WINED3D_OK;
3396}
3397
3398void CDECL wined3d_surface_set_palette(struct wined3d_surface *surface, struct wined3d_palette *palette)
3399{
3400 TRACE("surface %p, palette %p.\n", surface, palette);
3401
3402 if (surface->palette == palette)
3403 {
3404 TRACE("Nop palette change.\n");
3405 return;
3406 }
3407
3408 if (surface->palette && (surface->resource.usage & WINED3DUSAGE_RENDERTARGET))
3409 surface->palette->flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
3410
3411 surface->palette = palette;
3412
3413 if (palette)
3414 {
3415 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
3416 palette->flags |= WINEDDPCAPS_PRIMARYSURFACE;
3417
3418 surface->surface_ops->surface_realize_palette(surface);
3419 }
3420}
3421
3422HRESULT CDECL wined3d_surface_set_color_key(struct wined3d_surface *surface,
3423 DWORD flags, const struct wined3d_color_key *color_key)
3424{
3425 TRACE("surface %p, flags %#x, color_key %p.\n", surface, flags, color_key);
3426
3427 if (flags & WINEDDCKEY_COLORSPACE)
3428 {
3429 FIXME(" colorkey value not supported (%08x) !\n", flags);
3430 return WINED3DERR_INVALIDCALL;
3431 }
3432
3433 /* Dirtify the surface, but only if a key was changed. */
3434 if (color_key)
3435 {
3436 switch (flags & ~WINEDDCKEY_COLORSPACE)
3437 {
3438 case WINEDDCKEY_DESTBLT:
3439 surface->dst_blt_color_key = *color_key;
3440 surface->CKeyFlags |= WINEDDSD_CKDESTBLT;
3441 break;
3442
3443 case WINEDDCKEY_DESTOVERLAY:
3444 surface->dst_overlay_color_key = *color_key;
3445 surface->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
3446 break;
3447
3448 case WINEDDCKEY_SRCOVERLAY:
3449 surface->src_overlay_color_key = *color_key;
3450 surface->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
3451 break;
3452
3453 case WINEDDCKEY_SRCBLT:
3454 surface->src_blt_color_key = *color_key;
3455 surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
3456 break;
3457 }
3458 }
3459 else
3460 {
3461 switch (flags & ~WINEDDCKEY_COLORSPACE)
3462 {
3463 case WINEDDCKEY_DESTBLT:
3464 surface->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
3465 break;
3466
3467 case WINEDDCKEY_DESTOVERLAY:
3468 surface->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
3469 break;
3470
3471 case WINEDDCKEY_SRCOVERLAY:
3472 surface->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
3473 break;
3474
3475 case WINEDDCKEY_SRCBLT:
3476 surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
3477 break;
3478 }
3479 }
3480
3481 return WINED3D_OK;
3482}
3483
3484struct wined3d_palette * CDECL wined3d_surface_get_palette(const struct wined3d_surface *surface)
3485{
3486 TRACE("surface %p.\n", surface);
3487
3488 return surface->palette;
3489}
3490
3491DWORD CDECL wined3d_surface_get_pitch(const struct wined3d_surface *surface)
3492{
3493 const struct wined3d_format *format = surface->resource.format;
3494 DWORD pitch;
3495
3496 TRACE("surface %p.\n", surface);
3497
3498 if (surface->pitch)
3499 return surface->pitch;
3500
3501 if (format->flags & WINED3DFMT_FLAG_BLOCKS)
3502 {
3503 /* Since compressed formats are block based, pitch means the amount of
3504 * bytes to the next row of block rather than the next row of pixels. */
3505 UINT row_block_count = (surface->resource.width + format->block_width - 1) / format->block_width;
3506 pitch = row_block_count * format->block_byte_count;
3507 }
3508 else
3509 {
3510 unsigned char alignment = surface->resource.device->surface_alignment;
3511 pitch = surface->resource.format->byte_count * surface->resource.width; /* Bytes / row */
3512 pitch = (pitch + alignment - 1) & ~(alignment - 1);
3513 }
3514
3515 TRACE("Returning %u.\n", pitch);
3516
3517 return pitch;
3518}
3519
3520HRESULT CDECL wined3d_surface_set_mem(struct wined3d_surface *surface, void *mem, UINT pitch)
3521{
3522#ifndef VBOX_WITH_WDDM
3523 TRACE("surface %p, mem %p.\n", surface, mem);
3524
3525 if (surface->resource.map_count || (surface->flags & SFLAG_DCINUSE))
3526 {
3527 WARN("Surface is mapped or the DC is in use.\n");
3528 return WINED3DERR_INVALIDCALL;
3529 }
3530
3531 /* Render targets depend on their hdc, and we can't create an hdc on a user pointer. */
3532 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
3533 {
3534 ERR("Not supported on render targets.\n");
3535 return WINED3DERR_INVALIDCALL;
3536 }
3537
3538 if (mem && mem != surface->resource.allocatedMemory)
3539 {
3540 void *release = NULL;
3541
3542 /* Do I have to copy the old surface content? */
3543 if (surface->flags & SFLAG_DIBSECTION)
3544 {
3545 DeleteDC(surface->hDC);
3546 DeleteObject(surface->dib.DIBsection);
3547 surface->dib.bitmap_data = NULL;
3548 surface->resource.allocatedMemory = NULL;
3549 surface->hDC = NULL;
3550 surface->flags &= ~SFLAG_DIBSECTION;
3551 }
3552 else if (!(surface->flags & SFLAG_USERPTR))
3553 {
3554 release = surface->resource.heapMemory;
3555 surface->resource.heapMemory = NULL;
3556 }
3557 surface->resource.allocatedMemory = mem;
3558 surface->flags |= SFLAG_USERPTR;
3559
3560 /* Now the surface memory is most up do date. Invalidate drawable and texture. */
3561 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
3562
3563 /* For client textures OpenGL has to be notified. */
3564 if (surface->flags & SFLAG_CLIENT)
3565 surface_release_client_storage(surface);
3566
3567 /* Now free the old memory if any. */
3568 HeapFree(GetProcessHeap(), 0, release);
3569 }
3570 else if (surface->flags & SFLAG_USERPTR)
3571 {
3572 /* HeapMemory should be NULL already. */
3573 if (surface->resource.heapMemory)
3574 ERR("User pointer surface has heap memory allocated.\n");
3575
3576 if (!mem)
3577 {
3578 surface->resource.allocatedMemory = NULL;
3579 surface->flags &= ~(SFLAG_USERPTR | SFLAG_INSYSMEM);
3580
3581 if (surface->flags & SFLAG_CLIENT)
3582 surface_release_client_storage(surface);
3583
3584 surface_prepare_system_memory(surface);
3585 }
3586
3587 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
3588 }
3589
3590 surface->pitch = pitch;
3591
3592 return WINED3D_OK;
3593#else
3594 ERR("unsupported!");
3595 return E_FAIL;
3596#endif
3597}
3598
3599HRESULT CDECL wined3d_surface_set_overlay_position(struct wined3d_surface *surface, LONG x, LONG y)
3600{
3601 LONG w, h;
3602
3603 TRACE("surface %p, x %d, y %d.\n", surface, x, y);
3604
3605 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3606 {
3607 WARN("Not an overlay surface.\n");
3608 return WINEDDERR_NOTAOVERLAYSURFACE;
3609 }
3610
3611 w = surface->overlay_destrect.right - surface->overlay_destrect.left;
3612 h = surface->overlay_destrect.bottom - surface->overlay_destrect.top;
3613 surface->overlay_destrect.left = x;
3614 surface->overlay_destrect.top = y;
3615 surface->overlay_destrect.right = x + w;
3616 surface->overlay_destrect.bottom = y + h;
3617
3618 surface_draw_overlay(surface);
3619
3620 return WINED3D_OK;
3621}
3622
3623HRESULT CDECL wined3d_surface_get_overlay_position(const struct wined3d_surface *surface, LONG *x, LONG *y)
3624{
3625 TRACE("surface %p, x %p, y %p.\n", surface, x, y);
3626
3627 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3628 {
3629 TRACE("Not an overlay surface.\n");
3630 return WINEDDERR_NOTAOVERLAYSURFACE;
3631 }
3632
3633 if (!surface->overlay_dest)
3634 {
3635 TRACE("Overlay not visible.\n");
3636 *x = 0;
3637 *y = 0;
3638 return WINEDDERR_OVERLAYNOTVISIBLE;
3639 }
3640
3641 *x = surface->overlay_destrect.left;
3642 *y = surface->overlay_destrect.top;
3643
3644 TRACE("Returning position %d, %d.\n", *x, *y);
3645
3646 return WINED3D_OK;
3647}
3648
3649HRESULT CDECL wined3d_surface_update_overlay_z_order(struct wined3d_surface *surface,
3650 DWORD flags, struct wined3d_surface *ref)
3651{
3652 FIXME("surface %p, flags %#x, ref %p stub!\n", surface, flags, ref);
3653
3654 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3655 {
3656 TRACE("Not an overlay surface.\n");
3657 return WINEDDERR_NOTAOVERLAYSURFACE;
3658 }
3659
3660 return WINED3D_OK;
3661}
3662
3663HRESULT CDECL wined3d_surface_update_overlay(struct wined3d_surface *surface, const RECT *src_rect,
3664 struct wined3d_surface *dst_surface, const RECT *dst_rect, DWORD flags, const WINEDDOVERLAYFX *fx)
3665{
3666 TRACE("surface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
3667 surface, wine_dbgstr_rect(src_rect), dst_surface, wine_dbgstr_rect(dst_rect), flags, fx);
3668
3669 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3670 {
3671 WARN("Not an overlay surface.\n");
3672 return WINEDDERR_NOTAOVERLAYSURFACE;
3673 }
3674 else if (!dst_surface)
3675 {
3676 WARN("Dest surface is NULL.\n");
3677 return WINED3DERR_INVALIDCALL;
3678 }
3679
3680 if (src_rect)
3681 {
3682 surface->overlay_srcrect = *src_rect;
3683 }
3684 else
3685 {
3686 surface->overlay_srcrect.left = 0;
3687 surface->overlay_srcrect.top = 0;
3688 surface->overlay_srcrect.right = surface->resource.width;
3689 surface->overlay_srcrect.bottom = surface->resource.height;
3690 }
3691
3692 if (dst_rect)
3693 {
3694 surface->overlay_destrect = *dst_rect;
3695 }
3696 else
3697 {
3698 surface->overlay_destrect.left = 0;
3699 surface->overlay_destrect.top = 0;
3700 surface->overlay_destrect.right = dst_surface ? dst_surface->resource.width : 0;
3701 surface->overlay_destrect.bottom = dst_surface ? dst_surface->resource.height : 0;
3702 }
3703
3704 if (surface->overlay_dest && (surface->overlay_dest != dst_surface || flags & WINEDDOVER_HIDE))
3705 {
3706 surface->overlay_dest = NULL;
3707 list_remove(&surface->overlay_entry);
3708 }
3709
3710 if (flags & WINEDDOVER_SHOW)
3711 {
3712 if (surface->overlay_dest != dst_surface)
3713 {
3714 surface->overlay_dest = dst_surface;
3715 list_add_tail(&dst_surface->overlays, &surface->overlay_entry);
3716 }
3717 }
3718 else if (flags & WINEDDOVER_HIDE)
3719 {
3720 /* tests show that the rectangles are erased on hide */
3721 surface->overlay_srcrect.left = 0; surface->overlay_srcrect.top = 0;
3722 surface->overlay_srcrect.right = 0; surface->overlay_srcrect.bottom = 0;
3723 surface->overlay_destrect.left = 0; surface->overlay_destrect.top = 0;
3724 surface->overlay_destrect.right = 0; surface->overlay_destrect.bottom = 0;
3725 surface->overlay_dest = NULL;
3726 }
3727
3728 surface_draw_overlay(surface);
3729
3730 return WINED3D_OK;
3731}
3732
3733HRESULT CDECL wined3d_surface_update_desc(struct wined3d_surface *surface,
3734 UINT width, UINT height, enum wined3d_format_id format_id,
3735 enum wined3d_multisample_type multisample_type, UINT multisample_quality)
3736{
3737 struct wined3d_device *device = surface->resource.device;
3738 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
3739 const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
3740 UINT resource_size = wined3d_format_calculate_size(format, device->surface_alignment, width, height);
3741
3742 TRACE("surface %p, width %u, height %u, format %s, multisample_type %#x, multisample_quality %u.\n",
3743 surface, width, height, debug_d3dformat(format_id), multisample_type, multisample_type);
3744
3745 if (!resource_size)
3746 return WINED3DERR_INVALIDCALL;
3747
3748 if (device->d3d_initialized)
3749 surface->resource.resource_ops->resource_unload(&surface->resource);
3750
3751 if (surface->flags & SFLAG_DIBSECTION)
3752 {
3753 DeleteDC(surface->hDC);
3754 DeleteObject(surface->dib.DIBsection);
3755 surface->dib.bitmap_data = NULL;
3756 surface->flags &= ~SFLAG_DIBSECTION;
3757 }
3758
3759 surface->flags &= ~(SFLAG_LOCATIONS | SFLAG_USERPTR);
3760 surface->resource.allocatedMemory = NULL;
3761 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
3762 surface->resource.heapMemory = NULL;
3763
3764 surface->resource.width = width;
3765 surface->resource.height = height;
3766 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
3767 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
3768 {
3769 surface->pow2Width = width;
3770 surface->pow2Height = height;
3771 }
3772 else
3773 {
3774 surface->pow2Width = surface->pow2Height = 1;
3775 while (surface->pow2Width < width)
3776 surface->pow2Width <<= 1;
3777 while (surface->pow2Height < height)
3778 surface->pow2Height <<= 1;
3779 }
3780
3781 if (surface->pow2Width != width || surface->pow2Height != height)
3782 surface->flags |= SFLAG_NONPOW2;
3783 else
3784 surface->flags &= ~SFLAG_NONPOW2;
3785
3786 surface->resource.format = format;
3787 surface->resource.multisample_type = multisample_type;
3788 surface->resource.multisample_quality = multisample_quality;
3789 surface->resource.size = resource_size;
3790
3791 if (!surface_init_sysmem(surface))
3792 return E_OUTOFMEMORY;
3793
3794 return WINED3D_OK;
3795}
3796
3797static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst,
3798 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3799{
3800 unsigned short *dst_s;
3801 const float *src_f;
3802 unsigned int x, y;
3803
3804 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3805
3806 for (y = 0; y < h; ++y)
3807 {
3808 src_f = (const float *)(src + y * pitch_in);
3809 dst_s = (unsigned short *) (dst + y * pitch_out);
3810 for (x = 0; x < w; ++x)
3811 {
3812 dst_s[x] = float_32_to_16(src_f + x);
3813 }
3814 }
3815}
3816
3817static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
3818 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3819{
3820 static const unsigned char convert_5to8[] =
3821 {
3822 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
3823 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
3824 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
3825 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
3826 };
3827 static const unsigned char convert_6to8[] =
3828 {
3829 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
3830 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
3831 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
3832 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
3833 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
3834 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
3835 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
3836 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
3837 };
3838 unsigned int x, y;
3839
3840 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3841
3842 for (y = 0; y < h; ++y)
3843 {
3844 const WORD *src_line = (const WORD *)(src + y * pitch_in);
3845 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3846 for (x = 0; x < w; ++x)
3847 {
3848 WORD pixel = src_line[x];
3849 dst_line[x] = 0xff000000
3850 | convert_5to8[(pixel & 0xf800) >> 11] << 16
3851 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
3852 | convert_5to8[(pixel & 0x001f)];
3853 }
3854 }
3855}
3856
3857/* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
3858 * in both cases we're just setting the X / Alpha channel to 0xff. */
3859static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
3860 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3861{
3862 unsigned int x, y;
3863
3864 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3865
3866 for (y = 0; y < h; ++y)
3867 {
3868 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
3869 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3870
3871 for (x = 0; x < w; ++x)
3872 {
3873 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
3874 }
3875 }
3876}
3877
3878static inline BYTE cliptobyte(int x)
3879{
3880 return (BYTE)((x < 0) ? 0 : ((x > 255) ? 255 : x));
3881}
3882
3883static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
3884 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3885{
3886 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
3887 unsigned int x, y;
3888
3889 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3890
3891 for (y = 0; y < h; ++y)
3892 {
3893 const BYTE *src_line = src + y * pitch_in;
3894 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3895 for (x = 0; x < w; ++x)
3896 {
3897 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3898 * C = Y - 16; D = U - 128; E = V - 128;
3899 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3900 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3901 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3902 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3903 * U and V are shared between the pixels. */
3904 if (!(x & 1)) /* For every even pixel, read new U and V. */
3905 {
3906 d = (int) src_line[1] - 128;
3907 e = (int) src_line[3] - 128;
3908 r2 = 409 * e + 128;
3909 g2 = - 100 * d - 208 * e + 128;
3910 b2 = 516 * d + 128;
3911 }
3912 c2 = 298 * ((int) src_line[0] - 16);
3913 dst_line[x] = 0xff000000
3914 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
3915 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
3916 | cliptobyte((c2 + b2) >> 8); /* blue */
3917 /* Scale RGB values to 0..255 range,
3918 * then clip them if still not in range (may be negative),
3919 * then shift them within DWORD if necessary. */
3920 src_line += 2;
3921 }
3922 }
3923}
3924
3925static void convert_yuy2_r5g6b5(const BYTE *src, BYTE *dst,
3926 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3927{
3928 unsigned int x, y;
3929 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
3930
3931 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
3932
3933 for (y = 0; y < h; ++y)
3934 {
3935 const BYTE *src_line = src + y * pitch_in;
3936 WORD *dst_line = (WORD *)(dst + y * pitch_out);
3937 for (x = 0; x < w; ++x)
3938 {
3939 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3940 * C = Y - 16; D = U - 128; E = V - 128;
3941 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3942 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3943 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3944 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3945 * U and V are shared between the pixels. */
3946 if (!(x & 1)) /* For every even pixel, read new U and V. */
3947 {
3948 d = (int) src_line[1] - 128;
3949 e = (int) src_line[3] - 128;
3950 r2 = 409 * e + 128;
3951 g2 = - 100 * d - 208 * e + 128;
3952 b2 = 516 * d + 128;
3953 }
3954 c2 = 298 * ((int) src_line[0] - 16);
3955 dst_line[x] = (cliptobyte((c2 + r2) >> 8) >> 3) << 11 /* red */
3956 | (cliptobyte((c2 + g2) >> 8) >> 2) << 5 /* green */
3957 | (cliptobyte((c2 + b2) >> 8) >> 3); /* blue */
3958 /* Scale RGB values to 0..255 range,
3959 * then clip them if still not in range (may be negative),
3960 * then shift them within DWORD if necessary. */
3961 src_line += 2;
3962 }
3963 }
3964}
3965
3966struct d3dfmt_converter_desc
3967{
3968 enum wined3d_format_id from, to;
3969 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
3970};
3971
3972static const struct d3dfmt_converter_desc converters[] =
3973{
3974 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
3975 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
3976 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
3977 {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_B8G8R8A8_UNORM, convert_a8r8g8b8_x8r8g8b8},
3978 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
3979 {WINED3DFMT_YUY2, WINED3DFMT_B5G6R5_UNORM, convert_yuy2_r5g6b5},
3980};
3981
3982static inline const struct d3dfmt_converter_desc *find_converter(enum wined3d_format_id from,
3983 enum wined3d_format_id to)
3984{
3985 unsigned int i;
3986
3987 for (i = 0; i < (sizeof(converters) / sizeof(*converters)); ++i)
3988 {
3989 if (converters[i].from == from && converters[i].to == to)
3990 return &converters[i];
3991 }
3992
3993 return NULL;
3994}
3995
3996/*****************************************************************************
3997 * surface_convert_format
3998 *
3999 * Creates a duplicate of a surface in a different format. Is used by Blt to
4000 * blit between surfaces with different formats.
4001 *
4002 * Parameters
4003 * source: Source surface
4004 * fmt: Requested destination format
4005 *
4006 *****************************************************************************/
4007static struct wined3d_surface *surface_convert_format(struct wined3d_surface *source, enum wined3d_format_id to_fmt)
4008{
4009 struct wined3d_map_desc src_map, dst_map;
4010 const struct d3dfmt_converter_desc *conv;
4011 struct wined3d_surface *ret = NULL;
4012 HRESULT hr;
4013
4014 conv = find_converter(source->resource.format->id, to_fmt);
4015 if (!conv)
4016 {
4017 FIXME("Cannot find a conversion function from format %s to %s.\n",
4018 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
4019 return NULL;
4020 }
4021
4022 /* FIXME: Multisampled conversion? */
4023#ifdef VBOX_WITH_WDDM
4024 if (FAILED(hr = wined3d_surface_create(source->resource.device, source->resource.width, source->resource.height,
4025 to_fmt, 0, WINED3D_POOL_SCRATCH, WINED3D_MULTISAMPLE_NONE, 0,
4026 WINED3D_SURFACE_MAPPABLE | WINED3D_SURFACE_DISCARD, NULL, &wined3d_null_parent_ops, &ret
4027 , NULL, NULL
4028 )))
4029#else
4030 if (FAILED(hr = wined3d_surface_create(source->resource.device, source->resource.width, source->resource.height,
4031 to_fmt, 0, WINED3D_POOL_SCRATCH, WINED3D_MULTISAMPLE_NONE, 0,
4032 WINED3D_SURFACE_MAPPABLE | WINED3D_SURFACE_DISCARD, NULL, &wined3d_null_parent_ops, &ret)))
4033#endif
4034 {
4035 ERR("Failed to create a destination surface for conversion.\n");
4036 return NULL;
4037 }
4038
4039 memset(&src_map, 0, sizeof(src_map));
4040 memset(&dst_map, 0, sizeof(dst_map));
4041
4042 if (FAILED(hr = wined3d_surface_map(source, &src_map, NULL, WINED3D_MAP_READONLY)))
4043 {
4044 ERR("Failed to lock the source surface.\n");
4045 wined3d_surface_decref(ret);
4046 return NULL;
4047 }
4048 if (FAILED(hr = wined3d_surface_map(ret, &dst_map, NULL, WINED3D_MAP_READONLY)))
4049 {
4050 ERR("Failed to lock the destination surface.\n");
4051 wined3d_surface_unmap(source);
4052 wined3d_surface_decref(ret);
4053 return NULL;
4054 }
4055
4056 conv->convert(src_map.data, dst_map.data, src_map.row_pitch, dst_map.row_pitch,
4057 source->resource.width, source->resource.height);
4058
4059 wined3d_surface_unmap(ret);
4060 wined3d_surface_unmap(source);
4061
4062 return ret;
4063}
4064
4065static HRESULT _Blt_ColorFill(BYTE *buf, unsigned int width, unsigned int height,
4066 unsigned int bpp, UINT pitch, DWORD color)
4067{
4068 BYTE *first;
4069 unsigned int x, y;
4070
4071 /* Do first row */
4072
4073#define COLORFILL_ROW(type) \
4074do { \
4075 type *d = (type *)buf; \
4076 for (x = 0; x < width; ++x) \
4077 d[x] = (type)color; \
4078} while(0)
4079
4080 switch (bpp)
4081 {
4082 case 1:
4083 COLORFILL_ROW(BYTE);
4084 break;
4085
4086 case 2:
4087 COLORFILL_ROW(WORD);
4088 break;
4089
4090 case 3:
4091 {
4092 BYTE *d = buf;
4093 for (x = 0; x < width; ++x, d += 3)
4094 {
4095 d[0] = (color ) & 0xff;
4096 d[1] = (color >> 8) & 0xff;
4097 d[2] = (color >> 16) & 0xff;
4098 }
4099 break;
4100 }
4101 case 4:
4102 COLORFILL_ROW(DWORD);
4103 break;
4104
4105 default:
4106 FIXME("Color fill not implemented for bpp %u!\n", bpp * 8);
4107 return WINED3DERR_NOTAVAILABLE;
4108 }
4109
4110#undef COLORFILL_ROW
4111
4112 /* Now copy first row. */
4113 first = buf;
4114 for (y = 1; y < height; ++y)
4115 {
4116 buf += pitch;
4117 memcpy(buf, first, width * bpp);
4118 }
4119
4120 return WINED3D_OK;
4121}
4122
4123struct wined3d_surface * CDECL wined3d_surface_from_resource(struct wined3d_resource *resource)
4124{
4125 return surface_from_resource(resource);
4126}
4127
4128HRESULT CDECL wined3d_surface_unmap(struct wined3d_surface *surface)
4129{
4130 TRACE("surface %p.\n", surface);
4131
4132 if (!surface->resource.map_count)
4133 {
4134 WARN("Trying to unmap unmapped surface.\n");
4135 return WINEDDERR_NOTLOCKED;
4136 }
4137 --surface->resource.map_count;
4138
4139 surface->surface_ops->surface_unmap(surface);
4140
4141#ifdef VBOX_WITH_WDDM
4142 surface_shrc_unlock(surface);
4143#endif
4144
4145 return WINED3D_OK;
4146}
4147
4148HRESULT CDECL wined3d_surface_map(struct wined3d_surface *surface,
4149 struct wined3d_map_desc *map_desc, const RECT *rect, DWORD flags)
4150{
4151 const struct wined3d_format *format = surface->resource.format;
4152
4153 TRACE("surface %p, map_desc %p, rect %s, flags %#x.\n",
4154 surface, map_desc, wine_dbgstr_rect(rect), flags);
4155
4156 if (surface->resource.map_count)
4157 {
4158 WARN("Surface is already mapped.\n");
4159 return WINED3DERR_INVALIDCALL;
4160 }
4161
4162 if ((format->flags & WINED3DFMT_FLAG_BLOCKS) && rect
4163 && !surface_check_block_align(surface, rect))
4164 {
4165 WARN("Map rect %s is misaligned for %ux%u blocks.\n",
4166 wine_dbgstr_rect(rect), format->block_width, format->block_height);
4167
4168 if (surface->resource.pool == WINED3D_POOL_DEFAULT)
4169 return WINED3DERR_INVALIDCALL;
4170 }
4171
4172#ifdef VBOX_WITH_WDDM
4173 surface_shrc_lock(surface);
4174#endif
4175
4176 ++surface->resource.map_count;
4177
4178 if (!(surface->flags & SFLAG_LOCKABLE))
4179 WARN("Trying to lock unlockable surface.\n");
4180
4181 /* Performance optimization: Count how often a surface is mapped, if it is
4182 * mapped regularly do not throw away the system memory copy. This avoids
4183 * the need to download the surface from OpenGL all the time. The surface
4184 * is still downloaded if the OpenGL texture is changed. */
4185 if (!(surface->flags & SFLAG_DYNLOCK))
4186 {
4187 if (++surface->lockCount > MAXLOCKCOUNT)
4188 {
4189 TRACE("Surface is mapped regularly, not freeing the system memory copy any more.\n");
4190 surface->flags |= SFLAG_DYNLOCK;
4191 }
4192 }
4193
4194 surface->surface_ops->surface_map(surface, rect, flags);
4195
4196 if (format->flags & WINED3DFMT_FLAG_BROKEN_PITCH)
4197 map_desc->row_pitch = surface->resource.width * format->byte_count;
4198 else
4199 map_desc->row_pitch = wined3d_surface_get_pitch(surface);
4200 map_desc->slice_pitch = 0;
4201
4202 if (!rect)
4203 {
4204 map_desc->data = surface->resource.allocatedMemory;
4205 surface->lockedRect.left = 0;
4206 surface->lockedRect.top = 0;
4207 surface->lockedRect.right = surface->resource.width;
4208 surface->lockedRect.bottom = surface->resource.height;
4209 }
4210 else
4211 {
4212 if ((format->flags & (WINED3DFMT_FLAG_BLOCKS | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_BLOCKS)
4213 {
4214 /* Compressed textures are block based, so calculate the offset of
4215 * the block that contains the top-left pixel of the locked rectangle. */
4216 map_desc->data = surface->resource.allocatedMemory
4217 + ((rect->top / format->block_height) * map_desc->row_pitch)
4218 + ((rect->left / format->block_width) * format->block_byte_count);
4219 }
4220 else
4221 {
4222 map_desc->data = surface->resource.allocatedMemory
4223 + (map_desc->row_pitch * rect->top)
4224 + (rect->left * format->byte_count);
4225 }
4226 surface->lockedRect.left = rect->left;
4227 surface->lockedRect.top = rect->top;
4228 surface->lockedRect.right = rect->right;
4229 surface->lockedRect.bottom = rect->bottom;
4230 }
4231
4232 TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface->lockedRect));
4233 TRACE("Returning memory %p, pitch %u.\n", map_desc->data, map_desc->row_pitch);
4234
4235 return WINED3D_OK;
4236}
4237
4238HRESULT CDECL wined3d_surface_getdc(struct wined3d_surface *surface, HDC *dc)
4239{
4240 struct wined3d_map_desc map;
4241 HRESULT hr;
4242
4243 TRACE("surface %p, dc %p.\n", surface, dc);
4244
4245 if (surface->flags & SFLAG_USERPTR)
4246 {
4247 ERR("Not supported on surfaces with application-provided memory.\n");
4248 return WINEDDERR_NODC;
4249 }
4250
4251 /* Give more detailed info for ddraw. */
4252 if (surface->flags & SFLAG_DCINUSE)
4253 return WINEDDERR_DCALREADYCREATED;
4254
4255 /* Can't GetDC if the surface is locked. */
4256 if (surface->resource.map_count)
4257 return WINED3DERR_INVALIDCALL;
4258
4259 /* Create a DIB section if there isn't a dc yet. */
4260 if (!surface->hDC)
4261 {
4262 if (surface->flags & SFLAG_CLIENT)
4263 {
4264 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
4265 surface_release_client_storage(surface);
4266 }
4267 hr = surface_create_dib_section(surface);
4268 if (FAILED(hr))
4269 return WINED3DERR_INVALIDCALL;
4270
4271 /* Use the DIB section from now on if we are not using a PBO. */
4272 if (!(surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM)))
4273 {
4274 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
4275 surface->resource.heapMemory = NULL;
4276 surface->resource.allocatedMemory = surface->dib.bitmap_data;
4277 }
4278 }
4279
4280 /* Map the surface. */
4281 hr = wined3d_surface_map(surface, &map, NULL, 0);
4282 if (FAILED(hr))
4283 {
4284 ERR("Map failed, hr %#x.\n", hr);
4285 return hr;
4286 }
4287
4288 /* Sync the DIB with the PBO. This can't be done earlier because Map()
4289 * activates the allocatedMemory. */
4290#ifdef VBOX_WITH_WINE_FIX_PBOPSM
4291 if ((surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM)) == (SFLAG_PBO | SFLAG_PIN_SYSMEM))
4292#else
4293 if (surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM))
4294#endif
4295 memcpy(surface->dib.bitmap_data, surface->resource.allocatedMemory, surface->resource.size);
4296
4297 if (surface->resource.format->id == WINED3DFMT_P8_UINT
4298 || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
4299 {
4300 /* GetDC on palettized formats is unsupported in D3D9, and the method
4301 * is missing in D3D8, so this should only be used for DX <=7
4302 * surfaces (with non-device palettes). */
4303 const PALETTEENTRY *pal = NULL;
4304
4305 if (surface->palette)
4306 {
4307 pal = surface->palette->palents;
4308 }
4309 else
4310 {
4311 struct wined3d_swapchain *swapchain = surface->resource.device->swapchains[0];
4312 struct wined3d_surface *dds_primary = swapchain->front_buffer;
4313
4314 if (dds_primary && dds_primary->palette)
4315 pal = dds_primary->palette->palents;
4316 }
4317
4318 if (pal)
4319 {
4320 RGBQUAD col[256];
4321 unsigned int i;
4322
4323 for (i = 0; i < 256; ++i)
4324 {
4325 col[i].rgbRed = pal[i].peRed;
4326 col[i].rgbGreen = pal[i].peGreen;
4327 col[i].rgbBlue = pal[i].peBlue;
4328 col[i].rgbReserved = 0;
4329 }
4330 SetDIBColorTable(surface->hDC, 0, 256, col);
4331 }
4332 }
4333
4334 surface->flags |= SFLAG_DCINUSE;
4335
4336 *dc = surface->hDC;
4337 TRACE("Returning dc %p.\n", *dc);
4338
4339 return WINED3D_OK;
4340}
4341
4342HRESULT CDECL wined3d_surface_releasedc(struct wined3d_surface *surface, HDC dc)
4343{
4344 TRACE("surface %p, dc %p.\n", surface, dc);
4345
4346 if (!(surface->flags & SFLAG_DCINUSE))
4347 return WINEDDERR_NODC;
4348
4349 if (surface->hDC != dc)
4350 {
4351 WARN("Application tries to release invalid DC %p, surface DC is %p.\n",
4352 dc, surface->hDC);
4353 return WINEDDERR_NODC;
4354 }
4355
4356 /* Copy the contents of the DIB over to the PBO. */
4357#ifdef VBOX_WITH_WINE_FIX_PBOPSM
4358 if (((surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM)) == (SFLAG_PBO | SFLAG_PIN_SYSMEM)) && surface->resource.allocatedMemory)
4359#else
4360 if ((surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM)) && surface->resource.allocatedMemory)
4361#endif
4362 memcpy(surface->resource.allocatedMemory, surface->dib.bitmap_data, surface->resource.size);
4363
4364 /* We locked first, so unlock now. */
4365 wined3d_surface_unmap(surface);
4366
4367 surface->flags &= ~SFLAG_DCINUSE;
4368
4369 return WINED3D_OK;
4370}
4371
4372HRESULT CDECL wined3d_surface_flip(struct wined3d_surface *surface, struct wined3d_surface *override, DWORD flags)
4373{
4374 TRACE("surface %p, override %p, flags %#x.\n", surface, override, flags);
4375
4376 if (flags)
4377 {
4378 static UINT once;
4379 if (!once++)
4380 FIXME("Ignoring flags %#x.\n", flags);
4381 else
4382 WARN("Ignoring flags %#x.\n", flags);
4383 }
4384
4385 if (surface->swapchain)
4386 {
4387 ERR("Not supported on swapchain surfaces.\n");
4388 return WINEDDERR_NOTFLIPPABLE;
4389 }
4390
4391 /* Flipping is only supported on render targets and overlays. */
4392 if (!(surface->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_OVERLAY)))
4393 {
4394 WARN("Tried to flip a non-render target, non-overlay surface.\n");
4395 return WINEDDERR_NOTFLIPPABLE;
4396 }
4397
4398 flip_surface(surface, override);
4399
4400 /* Update overlays if they're visible. */
4401 if ((surface->resource.usage & WINED3DUSAGE_OVERLAY) && surface->overlay_dest)
4402 return surface_draw_overlay(surface);
4403
4404 return WINED3D_OK;
4405}
4406
4407/* Do not call while under the GL lock. */
4408void surface_internal_preload(struct wined3d_surface *surface, enum WINED3DSRGB srgb)
4409{
4410 struct wined3d_device *device = surface->resource.device;
4411
4412 TRACE("iface %p, srgb %#x.\n", surface, srgb);
4413
4414 if (surface->container)
4415 {
4416 struct wined3d_texture *texture = surface->container;
4417
4418 TRACE("Passing to container (%p).\n", texture);
4419 texture->texture_ops->texture_preload(texture, srgb);
4420 }
4421 else
4422 {
4423 struct wined3d_context *context;
4424
4425 TRACE("(%p) : About to load surface\n", surface);
4426
4427 /* TODO: Use already acquired context when possible. */
4428 context = context_acquire(device, NULL);
4429
4430 surface_load(surface, srgb == SRGB_SRGB);
4431
4432#ifndef VBOX
4433 if (surface->resource.pool == WINED3D_POOL_DEFAULT)
4434 {
4435 /* Tell opengl to try and keep this texture in video ram (well mostly) */
4436 GLclampf tmp;
4437 tmp = 0.9f;
4438 context->gl_info->gl_ops.gl.p_glPrioritizeTextures(1, &surface->texture_name, &tmp);
4439 }
4440#else
4441 /* chromium code on host fails to resolve texture name to texture obj,
4442 * most likely because the texture does not get created until it is bound
4443 * @todo: investigate */
4444#endif
4445 context_release(context);
4446 }
4447}
4448
4449/* Read the framebuffer back into the surface */
4450static void read_from_framebuffer(struct wined3d_surface *surface, const RECT *rect, void *dest, UINT pitch)
4451{
4452 struct wined3d_device *device = surface->resource.device;
4453 const struct wined3d_gl_info *gl_info;
4454 struct wined3d_context *context;
4455 BYTE *mem;
4456 GLint fmt;
4457 GLint type;
4458 BYTE *row, *top, *bottom;
4459 int i;
4460 BOOL bpp;
4461 RECT local_rect;
4462 BOOL srcIsUpsideDown;
4463 GLint rowLen = 0;
4464 GLint skipPix = 0;
4465 GLint skipRow = 0;
4466
4467 context = context_acquire(device, surface);
4468 context_apply_blit_state(context, device);
4469 gl_info = context->gl_info;
4470
4471 /* Select the correct read buffer, and give some debug output.
4472 * There is no need to keep track of the current read buffer or reset it, every part of the code
4473 * that reads sets the read buffer as desired.
4474 */
4475 if (surface_is_offscreen(surface))
4476 {
4477 /* Mapping the primary render target which is not on a swapchain.
4478 * Read from the back buffer. */
4479 TRACE("Mapping offscreen render target.\n");
4480 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
4481 srcIsUpsideDown = TRUE;
4482 }
4483 else
4484 {
4485 /* Onscreen surfaces are always part of a swapchain */
4486 GLenum buffer = surface_get_gl_buffer(surface);
4487 TRACE("Mapping %#x buffer.\n", buffer);
4488 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
4489 checkGLcall("glReadBuffer");
4490 srcIsUpsideDown = FALSE;
4491 }
4492
4493 /* TODO: Get rid of the extra rectangle comparison and construction of a full surface rectangle */
4494 if (!rect)
4495 {
4496 local_rect.left = 0;
4497 local_rect.top = 0;
4498 local_rect.right = surface->resource.width;
4499 local_rect.bottom = surface->resource.height;
4500 }
4501 else
4502 {
4503 local_rect = *rect;
4504 }
4505 /* TODO: Get rid of the extra GetPitch call, LockRect does that too. Cache the pitch */
4506
4507 switch (surface->resource.format->id)
4508 {
4509 case WINED3DFMT_P8_UINT:
4510 {
4511 if (primary_render_target_is_p8(device))
4512 {
4513 /* In case of P8 render targets the index is stored in the alpha component */
4514 fmt = GL_ALPHA;
4515 type = GL_UNSIGNED_BYTE;
4516 mem = dest;
4517 bpp = surface->resource.format->byte_count;
4518 }
4519 else
4520 {
4521 /* GL can't return palettized data, so read ARGB pixels into a
4522 * separate block of memory and convert them into palettized format
4523 * in software. Slow, but if the app means to use palettized render
4524 * targets and locks it...
4525 *
4526 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
4527 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
4528 * for the color channels when palettizing the colors.
4529 */
4530 fmt = GL_RGB;
4531 type = GL_UNSIGNED_BYTE;
4532 pitch *= 3;
4533 mem = HeapAlloc(GetProcessHeap(), 0, surface->resource.size * 3);
4534 if (!mem)
4535 {
4536 ERR("Out of memory\n");
4537 return;
4538 }
4539 bpp = surface->resource.format->byte_count * 3;
4540 }
4541 }
4542 break;
4543
4544 default:
4545 mem = dest;
4546 fmt = surface->resource.format->glFormat;
4547 type = surface->resource.format->glType;
4548 bpp = surface->resource.format->byte_count;
4549 }
4550
4551 if (surface->flags & SFLAG_PBO)
4552 {
4553 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
4554 checkGLcall("glBindBufferARB");
4555 if (mem)
4556 {
4557 ERR("mem not null for pbo -- unexpected\n");
4558 mem = NULL;
4559 }
4560 }
4561
4562 /* Save old pixel store pack state */
4563 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PACK_ROW_LENGTH, &rowLen);
4564 checkGLcall("glGetIntegerv");
4565 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PACK_SKIP_PIXELS, &skipPix);
4566 checkGLcall("glGetIntegerv");
4567 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PACK_SKIP_ROWS, &skipRow);
4568 checkGLcall("glGetIntegerv");
4569
4570 /* Setup pixel store pack state -- to glReadPixels into the correct place */
4571 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, surface->resource.width);
4572 checkGLcall("glPixelStorei");
4573 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_PIXELS, local_rect.left);
4574 checkGLcall("glPixelStorei");
4575 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_ROWS, local_rect.top);
4576 checkGLcall("glPixelStorei");
4577
4578 gl_info->gl_ops.gl.p_glReadPixels(local_rect.left,
4579 !srcIsUpsideDown ? (surface->resource.height - local_rect.bottom) : local_rect.top,
4580 local_rect.right - local_rect.left,
4581 local_rect.bottom - local_rect.top,
4582 fmt, type, mem);
4583 checkGLcall("glReadPixels");
4584
4585 /* Reset previous pixel store pack state */
4586 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, rowLen);
4587 checkGLcall("glPixelStorei");
4588 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_PIXELS, skipPix);
4589 checkGLcall("glPixelStorei");
4590 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_ROWS, skipRow);
4591 checkGLcall("glPixelStorei");
4592
4593 if (surface->flags & SFLAG_PBO)
4594 {
4595 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
4596 checkGLcall("glBindBufferARB");
4597
4598 /* Check if we need to flip the image. If we need to flip use glMapBufferARB
4599 * to get a pointer to it and perform the flipping in software. This is a lot
4600 * faster than calling glReadPixels for each line. In case we want more speed
4601 * we should rerender it flipped in a FBO and read the data back from the FBO. */
4602 if (!srcIsUpsideDown)
4603 {
4604 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
4605 checkGLcall("glBindBufferARB");
4606
4607 mem = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
4608 checkGLcall("glMapBufferARB");
4609 }
4610 }
4611
4612 /* TODO: Merge this with the palettization loop below for P8 targets */
4613 if(!srcIsUpsideDown) {
4614 UINT len, off;
4615 /* glReadPixels returns the image upside down, and there is no way to prevent this.
4616 Flip the lines in software */
4617 len = (local_rect.right - local_rect.left) * bpp;
4618 off = local_rect.left * bpp;
4619
4620 row = HeapAlloc(GetProcessHeap(), 0, len);
4621 if(!row) {
4622 ERR("Out of memory\n");
4623 if (surface->resource.format->id == WINED3DFMT_P8_UINT)
4624 HeapFree(GetProcessHeap(), 0, mem);
4625 return;
4626 }
4627
4628 top = mem + pitch * local_rect.top;
4629 bottom = mem + pitch * (local_rect.bottom - 1);
4630 for(i = 0; i < (local_rect.bottom - local_rect.top) / 2; i++) {
4631 memcpy(row, top + off, len);
4632 memcpy(top + off, bottom + off, len);
4633 memcpy(bottom + off, row, len);
4634 top += pitch;
4635 bottom -= pitch;
4636 }
4637 HeapFree(GetProcessHeap(), 0, row);
4638
4639 /* Unmap the temp PBO buffer */
4640 if (surface->flags & SFLAG_PBO)
4641 {
4642 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
4643 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
4644 }
4645 }
4646
4647 context_release(context);
4648
4649 /* For P8 textures we need to perform an inverse palette lookup. This is
4650 * done by searching for a palette index which matches the RGB value.
4651 * Note this isn't guaranteed to work when there are multiple entries for
4652 * the same color but we have no choice. In case of P8 render targets,
4653 * the index is stored in the alpha component so no conversion is needed. */
4654 if (surface->resource.format->id == WINED3DFMT_P8_UINT && !primary_render_target_is_p8(device))
4655 {
4656 const PALETTEENTRY *pal = NULL;
4657 DWORD width = pitch / 3;
4658 int x, y, c;
4659
4660 if (surface->palette)
4661 {
4662 pal = surface->palette->palents;
4663 }
4664 else
4665 {
4666 ERR("Palette is missing, cannot perform inverse palette lookup\n");
4667 HeapFree(GetProcessHeap(), 0, mem);
4668 return;
4669 }
4670
4671 for(y = local_rect.top; y < local_rect.bottom; y++) {
4672 for(x = local_rect.left; x < local_rect.right; x++) {
4673 /* start lines pixels */
4674 const BYTE *blue = mem + y * pitch + x * (sizeof(BYTE) * 3);
4675 const BYTE *green = blue + 1;
4676 const BYTE *red = green + 1;
4677
4678 for(c = 0; c < 256; c++) {
4679 if(*red == pal[c].peRed &&
4680 *green == pal[c].peGreen &&
4681 *blue == pal[c].peBlue)
4682 {
4683 *((BYTE *) dest + y * width + x) = c;
4684 break;
4685 }
4686 }
4687 }
4688 }
4689 HeapFree(GetProcessHeap(), 0, mem);
4690 }
4691}
4692
4693/* Read the framebuffer contents into a texture. Note that this function
4694 * doesn't do any kind of flipping. Using this on an onscreen surface will
4695 * result in a flipped D3D texture. */
4696void surface_load_fb_texture(struct wined3d_surface *surface, BOOL srgb)
4697{
4698 struct wined3d_device *device = surface->resource.device;
4699 const struct wined3d_gl_info *gl_info;
4700 struct wined3d_context *context;
4701
4702 context = context_acquire(device, surface);
4703 gl_info = context->gl_info;
4704 device_invalidate_state(device, STATE_FRAMEBUFFER);
4705
4706 surface_prepare_texture(surface, context, srgb);
4707 surface_bind_and_dirtify(surface, context, srgb);
4708
4709 TRACE("Reading back offscreen render target %p.\n", surface);
4710
4711 if (surface_is_offscreen(surface))
4712 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
4713 else
4714 gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(surface));
4715 checkGLcall("glReadBuffer");
4716
4717 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(surface->texture_target, surface->texture_level,
4718 0, 0, 0, 0, surface->resource.width, surface->resource.height);
4719 checkGLcall("glCopyTexSubImage2D");
4720
4721 context_release(context);
4722}
4723
4724/* Context activation is done by the caller. */
4725static void surface_prepare_texture_internal(struct wined3d_surface *surface,
4726 struct wined3d_context *context, BOOL srgb)
4727{
4728 DWORD alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED;
4729 enum wined3d_conversion_type convert;
4730 struct wined3d_format format;
4731
4732 if (surface->flags & alloc_flag) return;
4733
4734 d3dfmt_get_conv(surface, TRUE, TRUE, &format, &convert);
4735 if (convert != WINED3D_CT_NONE || format.convert)
4736 surface->flags |= SFLAG_CONVERTED;
4737 else surface->flags &= ~SFLAG_CONVERTED;
4738
4739 surface_bind_and_dirtify(surface, context, srgb);
4740 surface_allocate_surface(surface, context->gl_info, &format, srgb);
4741 surface->flags |= alloc_flag;
4742}
4743
4744/* Context activation is done by the caller. */
4745void surface_prepare_texture(struct wined3d_surface *surface, struct wined3d_context *context, BOOL srgb)
4746{
4747 if (surface->container)
4748 {
4749 struct wined3d_texture *texture = surface->container;
4750 UINT sub_count = texture->level_count * texture->layer_count;
4751 UINT i;
4752
4753 TRACE("surface %p is a subresource of texture %p.\n", surface, texture);
4754
4755 for (i = 0; i < sub_count; ++i)
4756 {
4757 struct wined3d_surface *s = surface_from_resource(texture->sub_resources[i]);
4758 surface_prepare_texture_internal(s, context, srgb);
4759 }
4760
4761 return;
4762 }
4763
4764 surface_prepare_texture_internal(surface, context, srgb);
4765}
4766
4767void surface_prepare_rb(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info, BOOL multisample)
4768{
4769 if (multisample)
4770 {
4771 if (surface->rb_multisample)
4772 return;
4773
4774 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_multisample);
4775 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_multisample);
4776 gl_info->fbo_ops.glRenderbufferStorageMultisample(GL_RENDERBUFFER, surface->resource.multisample_type,
4777 surface->resource.format->glInternal, surface->pow2Width, surface->pow2Height);
4778 TRACE("Created multisample rb %u.\n", surface->rb_multisample);
4779 }
4780 else
4781 {
4782 if (surface->rb_resolved)
4783 return;
4784
4785 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_resolved);
4786 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_resolved);
4787 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, surface->resource.format->glInternal,
4788 surface->pow2Width, surface->pow2Height);
4789 TRACE("Created resolved rb %u.\n", surface->rb_resolved);
4790 }
4791}
4792
4793static void flush_to_framebuffer_drawpixels(struct wined3d_surface *surface,
4794 const RECT *rect, GLenum fmt, GLenum type, UINT bpp, const BYTE *mem)
4795{
4796 struct wined3d_device *device = surface->resource.device;
4797 UINT pitch = wined3d_surface_get_pitch(surface);
4798 const struct wined3d_gl_info *gl_info;
4799 struct wined3d_context *context;
4800 RECT local_rect;
4801 UINT w, h;
4802
4803 surface_get_rect(surface, rect, &local_rect);
4804
4805 mem += local_rect.top * pitch + local_rect.left * bpp;
4806 w = local_rect.right - local_rect.left;
4807 h = local_rect.bottom - local_rect.top;
4808
4809 /* Activate the correct context for the render target */
4810 context = context_acquire(device, surface);
4811 context_apply_blit_state(context, device);
4812 gl_info = context->gl_info;
4813
4814 if (!surface_is_offscreen(surface))
4815 {
4816 GLenum buffer = surface_get_gl_buffer(surface);
4817 TRACE("Unlocking %#x buffer.\n", buffer);
4818 context_set_draw_buffer(context, buffer);
4819
4820#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
4821 surface_translate_drawable_coords(surface, context->win_handle, &local_rect);
4822#else
4823 surface_translate_drawable_coords(surface, context->swapchain->win_handle, &local_rect);
4824#endif
4825 gl_info->gl_ops.gl.p_glPixelZoom(1.0f, -1.0f);
4826 }
4827 else
4828 {
4829 /* Primary offscreen render target */
4830 TRACE("Offscreen render target.\n");
4831 context_set_draw_buffer(context, device->offscreenBuffer);
4832
4833 gl_info->gl_ops.gl.p_glPixelZoom(1.0f, 1.0f);
4834 }
4835
4836 gl_info->gl_ops.gl.p_glRasterPos3i(local_rect.left, local_rect.top, 1);
4837 checkGLcall("glRasterPos3i");
4838
4839 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
4840 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, surface->resource.width);
4841
4842 if (surface->flags & SFLAG_PBO)
4843 {
4844 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
4845 checkGLcall("glBindBufferARB");
4846 }
4847
4848 gl_info->gl_ops.gl.p_glDrawPixels(w, h, fmt, type, mem);
4849 checkGLcall("glDrawPixels");
4850
4851 if (surface->flags & SFLAG_PBO)
4852 {
4853 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
4854 checkGLcall("glBindBufferARB");
4855 }
4856
4857 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
4858 checkGLcall("glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)");
4859
4860 if (wined3d_settings.strict_draw_ordering
4861 || (surface->swapchain && surface->swapchain->front_buffer == surface))
4862 gl_info->gl_ops.gl.p_glFlush();
4863
4864 context_release(context);
4865}
4866
4867static BOOL color_in_range(const struct wined3d_color_key *color_key, DWORD color)
4868{
4869 /* FIXME: Is this really how color keys are supposed to work? I think it
4870 * makes more sense to compare the individual channels. */
4871 return color >= color_key->color_space_low_value
4872 && color <= color_key->color_space_high_value;
4873}
4874
4875void d3dfmt_p8_init_palette(const struct wined3d_surface *surface, BYTE table[256][4], BOOL colorkey)
4876{
4877 const struct wined3d_device *device = surface->resource.device;
4878 const struct wined3d_palette *pal = surface->palette;
4879 BOOL index_in_alpha = FALSE;
4880 unsigned int i;
4881
4882 /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
4883 * Reading back the RGB output each lockrect (each frame as they lock the whole screen)
4884 * is slow. Further RGB->P8 conversion is not possible because palettes can have
4885 * duplicate entries. Store the color key in the unused alpha component to speed the
4886 * download up and to make conversion unneeded. */
4887 index_in_alpha = primary_render_target_is_p8(device);
4888
4889 if (!pal)
4890 {
4891 FIXME("No palette set.\n");
4892 if (index_in_alpha)
4893 {
4894 /* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
4895 * there's no palette at this time. */
4896 for (i = 0; i < 256; i++) table[i][3] = i;
4897 }
4898 }
4899 else
4900 {
4901 TRACE("Using surface palette %p\n", pal);
4902 /* Get the surface's palette */
4903 for (i = 0; i < 256; ++i)
4904 {
4905 table[i][0] = pal->palents[i].peRed;
4906 table[i][1] = pal->palents[i].peGreen;
4907 table[i][2] = pal->palents[i].peBlue;
4908
4909 /* When index_in_alpha is set the palette index is stored in the
4910 * alpha component. In case of a readback we can then read
4911 * GL_ALPHA. Color keying is handled in BltOverride using a
4912 * GL_ALPHA_TEST using GL_NOT_EQUAL. In case of index_in_alpha the
4913 * color key itself is passed to glAlphaFunc in other cases the
4914 * alpha component of pixels that should be masked away is set to 0. */
4915 if (index_in_alpha)
4916 table[i][3] = i;
4917 else if (colorkey && color_in_range(&surface->src_blt_color_key, i))
4918 table[i][3] = 0x00;
4919 else if (pal->flags & WINEDDPCAPS_ALPHA)
4920 table[i][3] = pal->palents[i].peFlags;
4921 else
4922 table[i][3] = 0xff;
4923 }
4924 }
4925}
4926
4927static HRESULT d3dfmt_convert_surface(const BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height,
4928 UINT outpitch, enum wined3d_conversion_type conversion_type, struct wined3d_surface *surface)
4929{
4930 const BYTE *source;
4931 BYTE *dest;
4932
4933 TRACE("src %p, dst %p, pitch %u, width %u, height %u, outpitch %u, conversion_type %#x, surface %p.\n",
4934 src, dst, pitch, width, height, outpitch, conversion_type, surface);
4935
4936 switch (conversion_type)
4937 {
4938 case WINED3D_CT_NONE:
4939 {
4940 memcpy(dst, src, pitch * height);
4941 break;
4942 }
4943
4944 case WINED3D_CT_PALETTED:
4945 case WINED3D_CT_PALETTED_CK:
4946 {
4947 BYTE table[256][4];
4948 unsigned int x, y;
4949
4950 d3dfmt_p8_init_palette(surface, table, (conversion_type == WINED3D_CT_PALETTED_CK));
4951
4952 for (y = 0; y < height; y++)
4953 {
4954 source = src + pitch * y;
4955 dest = dst + outpitch * y;
4956 /* This is an 1 bpp format, using the width here is fine */
4957 for (x = 0; x < width; x++) {
4958 BYTE color = *source++;
4959 *dest++ = table[color][0];
4960 *dest++ = table[color][1];
4961 *dest++ = table[color][2];
4962 *dest++ = table[color][3];
4963 }
4964 }
4965 }
4966 break;
4967
4968 case WINED3D_CT_CK_565:
4969 {
4970 /* Converting the 565 format in 5551 packed to emulate color-keying.
4971
4972 Note : in all these conversion, it would be best to average the averaging
4973 pixels to get the color of the pixel that will be color-keyed to
4974 prevent 'color bleeding'. This will be done later on if ever it is
4975 too visible.
4976
4977 Note2: Nvidia documents say that their driver does not support alpha + color keying
4978 on the same surface and disables color keying in such a case
4979 */
4980 unsigned int x, y;
4981 const WORD *Source;
4982 WORD *Dest;
4983
4984 TRACE("Color keyed 565\n");
4985
4986 for (y = 0; y < height; y++) {
4987 Source = (const WORD *)(src + y * pitch);
4988 Dest = (WORD *) (dst + y * outpitch);
4989 for (x = 0; x < width; x++ ) {
4990 WORD color = *Source++;
4991 *Dest = ((color & 0xffc0) | ((color & 0x1f) << 1));
4992 if (!color_in_range(&surface->src_blt_color_key, color))
4993 *Dest |= 0x0001;
4994 Dest++;
4995 }
4996 }
4997 }
4998 break;
4999
5000 case WINED3D_CT_CK_5551:
5001 {
5002 /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
5003 unsigned int x, y;
5004 const WORD *Source;
5005 WORD *Dest;
5006 TRACE("Color keyed 5551\n");
5007 for (y = 0; y < height; y++) {
5008 Source = (const WORD *)(src + y * pitch);
5009 Dest = (WORD *) (dst + y * outpitch);
5010 for (x = 0; x < width; x++ ) {
5011 WORD color = *Source++;
5012 *Dest = color;
5013 if (!color_in_range(&surface->src_blt_color_key, color))
5014 *Dest |= (1 << 15);
5015 else
5016 *Dest &= ~(1 << 15);
5017 Dest++;
5018 }
5019 }
5020 }
5021 break;
5022
5023 case WINED3D_CT_CK_RGB24:
5024 {
5025 /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
5026 unsigned int x, y;
5027 for (y = 0; y < height; y++)
5028 {
5029 source = src + pitch * y;
5030 dest = dst + outpitch * y;
5031 for (x = 0; x < width; x++) {
5032 DWORD color = ((DWORD)source[0] << 16) + ((DWORD)source[1] << 8) + (DWORD)source[2] ;
5033 DWORD dstcolor = color << 8;
5034 if (!color_in_range(&surface->src_blt_color_key, color))
5035 dstcolor |= 0xff;
5036 *(DWORD*)dest = dstcolor;
5037 source += 3;
5038 dest += 4;
5039 }
5040 }
5041 }
5042 break;
5043
5044 case WINED3D_CT_RGB32_888:
5045 {
5046 /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
5047 unsigned int x, y;
5048 for (y = 0; y < height; y++)
5049 {
5050 source = src + pitch * y;
5051 dest = dst + outpitch * y;
5052 for (x = 0; x < width; x++) {
5053 DWORD color = 0xffffff & *(const DWORD*)source;
5054 DWORD dstcolor = color << 8;
5055 if (!color_in_range(&surface->src_blt_color_key, color))
5056 dstcolor |= 0xff;
5057 *(DWORD*)dest = dstcolor;
5058 source += 4;
5059 dest += 4;
5060 }
5061 }
5062 }
5063 break;
5064
5065 case WINED3D_CT_CK_ARGB32:
5066 {
5067 unsigned int x, y;
5068 for (y = 0; y < height; ++y)
5069 {
5070 source = src + pitch * y;
5071 dest = dst + outpitch * y;
5072 for (x = 0; x < width; ++x)
5073 {
5074 DWORD color = *(const DWORD *)source;
5075 if (color_in_range(&surface->src_blt_color_key, color))
5076 color &= ~0xff000000;
5077 *(DWORD*)dest = color;
5078 source += 4;
5079 dest += 4;
5080 }
5081 }
5082 }
5083 break;
5084
5085 default:
5086 ERR("Unsupported conversion type %#x.\n", conversion_type);
5087 }
5088 return WINED3D_OK;
5089}
5090
5091void flip_surface(struct wined3d_surface *front, struct wined3d_surface *back)
5092{
5093 /* Flip the surface contents */
5094 /* Flip the DC */
5095 {
5096 HDC tmp;
5097 tmp = front->hDC;
5098 front->hDC = back->hDC;
5099 back->hDC = tmp;
5100 }
5101
5102 /* Flip the DIBsection */
5103 {
5104 HBITMAP tmp = front->dib.DIBsection;
5105 front->dib.DIBsection = back->dib.DIBsection;
5106 back->dib.DIBsection = tmp;
5107 }
5108
5109 /* Flip the surface data */
5110 {
5111 void* tmp;
5112
5113 tmp = front->dib.bitmap_data;
5114 front->dib.bitmap_data = back->dib.bitmap_data;
5115 back->dib.bitmap_data = tmp;
5116
5117 tmp = front->resource.allocatedMemory;
5118 front->resource.allocatedMemory = back->resource.allocatedMemory;
5119 back->resource.allocatedMemory = tmp;
5120
5121 tmp = front->resource.heapMemory;
5122 front->resource.heapMemory = back->resource.heapMemory;
5123 back->resource.heapMemory = tmp;
5124 }
5125
5126 /* Flip the PBO */
5127 {
5128 GLuint tmp_pbo = front->pbo;
5129 front->pbo = back->pbo;
5130 back->pbo = tmp_pbo;
5131 }
5132
5133 /* Flip the opengl texture */
5134 {
5135 GLuint tmp;
5136
5137 tmp = back->texture_name;
5138 back->texture_name = front->texture_name;
5139 front->texture_name = tmp;
5140
5141 tmp = back->texture_name_srgb;
5142 back->texture_name_srgb = front->texture_name_srgb;
5143 front->texture_name_srgb = tmp;
5144
5145 tmp = back->rb_multisample;
5146 back->rb_multisample = front->rb_multisample;
5147 front->rb_multisample = tmp;
5148
5149 tmp = back->rb_resolved;
5150 back->rb_resolved = front->rb_resolved;
5151 front->rb_resolved = tmp;
5152
5153 resource_unload(&back->resource);
5154 resource_unload(&front->resource);
5155 }
5156
5157 {
5158 DWORD tmp_flags = back->flags;
5159 back->flags = front->flags;
5160 front->flags = tmp_flags;
5161 }
5162}
5163
5164/* Does a direct frame buffer -> texture copy. Stretching is done with single
5165 * pixel copy calls. */
5166static void fb_copy_to_texture_direct(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
5167 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
5168{
5169 struct wined3d_device *device = dst_surface->resource.device;
5170 const struct wined3d_gl_info *gl_info;
5171 float xrel, yrel;
5172 struct wined3d_context *context;
5173 BOOL upsidedown = FALSE;
5174 RECT dst_rect = *dst_rect_in;
5175 GLenum dst_target;
5176
5177 if (dst_surface->container)
5178 dst_target = dst_surface->container->target;
5179 else
5180 dst_target = dst_surface->texture_target;
5181
5182 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
5183 * glCopyTexSubImage is a bit picky about the parameters we pass to it
5184 */
5185 if(dst_rect.top > dst_rect.bottom) {
5186 UINT tmp = dst_rect.bottom;
5187 dst_rect.bottom = dst_rect.top;
5188 dst_rect.top = tmp;
5189 upsidedown = TRUE;
5190 }
5191
5192 context = context_acquire(device, src_surface);
5193 gl_info = context->gl_info;
5194 context_apply_blit_state(context, device);
5195 surface_internal_preload(dst_surface, SRGB_RGB);
5196
5197 /* Bind the target texture */
5198 context_bind_texture(context, dst_target, dst_surface->texture_name);
5199 if (surface_is_offscreen(src_surface))
5200 {
5201 TRACE("Reading from an offscreen target\n");
5202 upsidedown = !upsidedown;
5203 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
5204 }
5205 else
5206 {
5207 gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(src_surface));
5208 }
5209 checkGLcall("glReadBuffer");
5210
5211 xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
5212 yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
5213
5214 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
5215 {
5216 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
5217
5218 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
5219 ERR("Texture filtering not supported in direct blit.\n");
5220 }
5221 else if ((filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
5222 && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
5223 {
5224 ERR("Texture filtering not supported in direct blit\n");
5225 }
5226
5227 if (upsidedown
5228 && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
5229 && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
5230 {
5231 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
5232 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
5233 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
5234 src_rect->left, src_surface->resource.height - src_rect->bottom,
5235 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
5236 }
5237 else
5238 {
5239 LONG row;
5240 UINT yoffset = src_surface->resource.height - src_rect->top + dst_rect.top - 1;
5241 /* I have to process this row by row to swap the image,
5242 * otherwise it would be upside down, so stretching in y direction
5243 * doesn't cost extra time
5244 *
5245 * However, stretching in x direction can be avoided if not necessary
5246 */
5247 for(row = dst_rect.top; row < dst_rect.bottom; row++) {
5248 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
5249 {
5250 /* Well, that stuff works, but it's very slow.
5251 * find a better way instead
5252 */
5253 LONG col;
5254
5255 for (col = dst_rect.left; col < dst_rect.right; ++col)
5256 {
5257 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
5258 dst_rect.left + col /* x offset */, row /* y offset */,
5259 src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
5260 }
5261 }
5262 else
5263 {
5264 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
5265 dst_rect.left /* x offset */, row /* y offset */,
5266 src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
5267 }
5268 }
5269 }
5270 checkGLcall("glCopyTexSubImage2D");
5271
5272 context_release(context);
5273
5274 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
5275 * path is never entered
5276 */
5277 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
5278}
5279
5280/* Uses the hardware to stretch and flip the image */
5281static void fb_copy_to_texture_hwstretch(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
5282 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
5283{
5284 struct wined3d_device *device = dst_surface->resource.device;
5285 GLuint src, backup = 0;
5286 float left, right, top, bottom; /* Texture coordinates */
5287 UINT fbwidth = src_surface->resource.width;
5288 UINT fbheight = src_surface->resource.height;
5289 const struct wined3d_gl_info *gl_info;
5290 struct wined3d_context *context;
5291 GLenum drawBuffer = GL_BACK;
5292 GLenum texture_target;
5293 BOOL noBackBufferBackup;
5294 BOOL src_offscreen;
5295 BOOL upsidedown = FALSE;
5296 RECT dst_rect = *dst_rect_in;
5297
5298 TRACE("Using hwstretch blit\n");
5299 /* Activate the Proper context for reading from the source surface, set it up for blitting */
5300 context = context_acquire(device, src_surface);
5301 gl_info = context->gl_info;
5302 context_apply_blit_state(context, device);
5303 surface_internal_preload(dst_surface, SRGB_RGB);
5304
5305 src_offscreen = surface_is_offscreen(src_surface);
5306 noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
5307 if (!noBackBufferBackup && !src_surface->texture_name)
5308 {
5309 /* Get it a description */
5310 surface_internal_preload(src_surface, SRGB_RGB);
5311 }
5312
5313 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
5314 * This way we don't have to wait for the 2nd readback to finish to leave this function.
5315 */
5316 if (context->aux_buffers >= 2)
5317 {
5318 /* Got more than one aux buffer? Use the 2nd aux buffer */
5319 drawBuffer = GL_AUX1;
5320 }
5321 else if ((!src_offscreen || device->offscreenBuffer == GL_BACK) && context->aux_buffers >= 1)
5322 {
5323 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
5324 drawBuffer = GL_AUX0;
5325 }
5326
5327 if (noBackBufferBackup)
5328 {
5329 gl_info->gl_ops.gl.p_glGenTextures(1, &backup);
5330 checkGLcall("glGenTextures");
5331 context_bind_texture(context, GL_TEXTURE_2D, backup);
5332 texture_target = GL_TEXTURE_2D;
5333 }
5334 else
5335 {
5336 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
5337 * we are reading from the back buffer, the backup can be used as source texture
5338 */
5339 texture_target = src_surface->texture_target;
5340 context_bind_texture(context, texture_target, src_surface->texture_name);
5341 gl_info->gl_ops.gl.p_glEnable(texture_target);
5342 checkGLcall("glEnable(texture_target)");
5343
5344 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
5345 src_surface->flags &= ~SFLAG_INTEXTURE;
5346 }
5347
5348 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
5349 * glCopyTexSubImage is a bit picky about the parameters we pass to it
5350 */
5351 if(dst_rect.top > dst_rect.bottom) {
5352 UINT tmp = dst_rect.bottom;
5353 dst_rect.bottom = dst_rect.top;
5354 dst_rect.top = tmp;
5355 upsidedown = TRUE;
5356 }
5357
5358 if (src_offscreen)
5359 {
5360 TRACE("Reading from an offscreen target\n");
5361 upsidedown = !upsidedown;
5362 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
5363 }
5364 else
5365 {
5366 gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(src_surface));
5367 }
5368
5369 /* TODO: Only back up the part that will be overwritten */
5370 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target, 0, 0, 0, 0, 0, fbwidth, fbheight);
5371
5372 checkGLcall("glCopyTexSubImage2D");
5373
5374 /* No issue with overriding these - the sampler is dirty due to blit usage */
5375 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER,
5376 wined3d_gl_mag_filter(magLookup, filter));
5377 checkGLcall("glTexParameteri");
5378 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
5379 wined3d_gl_min_mip_filter(minMipLookup, filter, WINED3D_TEXF_NONE));
5380 checkGLcall("glTexParameteri");
5381
5382 if (!src_surface->swapchain || src_surface == src_surface->swapchain->back_buffers[0])
5383 {
5384 src = backup ? backup : src_surface->texture_name;
5385 }
5386 else
5387 {
5388 gl_info->gl_ops.gl.p_glReadBuffer(GL_FRONT);
5389 checkGLcall("glReadBuffer(GL_FRONT)");
5390
5391 gl_info->gl_ops.gl.p_glGenTextures(1, &src);
5392 checkGLcall("glGenTextures(1, &src)");
5393 context_bind_texture(context, GL_TEXTURE_2D, src);
5394
5395 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
5396 * out for power of 2 sizes
5397 */
5398 gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_surface->pow2Width,
5399 src_surface->pow2Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
5400 checkGLcall("glTexImage2D");
5401 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, fbwidth, fbheight);
5402
5403 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5404 checkGLcall("glTexParameteri");
5405 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5406 checkGLcall("glTexParameteri");
5407
5408 gl_info->gl_ops.gl.p_glReadBuffer(GL_BACK);
5409 checkGLcall("glReadBuffer(GL_BACK)");
5410
5411 if (texture_target != GL_TEXTURE_2D)
5412 {
5413 gl_info->gl_ops.gl.p_glDisable(texture_target);
5414 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
5415 texture_target = GL_TEXTURE_2D;
5416 }
5417 }
5418 checkGLcall("glEnd and previous");
5419
5420 left = src_rect->left;
5421 right = src_rect->right;
5422
5423 if (!upsidedown)
5424 {
5425 top = src_surface->resource.height - src_rect->top;
5426 bottom = src_surface->resource.height - src_rect->bottom;
5427 }
5428 else
5429 {
5430 top = src_surface->resource.height - src_rect->bottom;
5431 bottom = src_surface->resource.height - src_rect->top;
5432 }
5433
5434 if (src_surface->flags & SFLAG_NORMCOORD)
5435 {
5436 left /= src_surface->pow2Width;
5437 right /= src_surface->pow2Width;
5438 top /= src_surface->pow2Height;
5439 bottom /= src_surface->pow2Height;
5440 }
5441
5442 /* draw the source texture stretched and upside down. The correct surface is bound already */
5443 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
5444 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
5445
5446 context_set_draw_buffer(context, drawBuffer);
5447 gl_info->gl_ops.gl.p_glReadBuffer(drawBuffer);
5448
5449 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
5450 /* bottom left */
5451 gl_info->gl_ops.gl.p_glTexCoord2f(left, bottom);
5452 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
5453
5454 /* top left */
5455 gl_info->gl_ops.gl.p_glTexCoord2f(left, top);
5456 gl_info->gl_ops.gl.p_glVertex2i(0, dst_rect.bottom - dst_rect.top);
5457
5458 /* top right */
5459 gl_info->gl_ops.gl.p_glTexCoord2f(right, top);
5460 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
5461
5462 /* bottom right */
5463 gl_info->gl_ops.gl.p_glTexCoord2f(right, bottom);
5464 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, 0);
5465 gl_info->gl_ops.gl.p_glEnd();
5466 checkGLcall("glEnd and previous");
5467
5468 if (texture_target != dst_surface->texture_target)
5469 {
5470 gl_info->gl_ops.gl.p_glDisable(texture_target);
5471 gl_info->gl_ops.gl.p_glEnable(dst_surface->texture_target);
5472 texture_target = dst_surface->texture_target;
5473 }
5474
5475 /* Now read the stretched and upside down image into the destination texture */
5476 context_bind_texture(context, texture_target, dst_surface->texture_name);
5477 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target,
5478 0,
5479 dst_rect.left, dst_rect.top, /* xoffset, yoffset */
5480 0, 0, /* We blitted the image to the origin */
5481 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
5482 checkGLcall("glCopyTexSubImage2D");
5483
5484 if (drawBuffer == GL_BACK)
5485 {
5486 /* Write the back buffer backup back. */
5487 if (backup)
5488 {
5489 if (texture_target != GL_TEXTURE_2D)
5490 {
5491 gl_info->gl_ops.gl.p_glDisable(texture_target);
5492 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
5493 texture_target = GL_TEXTURE_2D;
5494 }
5495 context_bind_texture(context, GL_TEXTURE_2D, backup);
5496 }
5497 else
5498 {
5499 if (texture_target != src_surface->texture_target)
5500 {
5501 gl_info->gl_ops.gl.p_glDisable(texture_target);
5502 gl_info->gl_ops.gl.p_glEnable(src_surface->texture_target);
5503 texture_target = src_surface->texture_target;
5504 }
5505 context_bind_texture(context, src_surface->texture_target, src_surface->texture_name);
5506 }
5507
5508 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
5509 /* top left */
5510 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, 0.0f);
5511 gl_info->gl_ops.gl.p_glVertex2i(0, fbheight);
5512
5513 /* bottom left */
5514 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, (float)fbheight / (float)src_surface->pow2Height);
5515 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
5516
5517 /* bottom right */
5518 gl_info->gl_ops.gl.p_glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width,
5519 (float)fbheight / (float)src_surface->pow2Height);
5520 gl_info->gl_ops.gl.p_glVertex2i(fbwidth, 0);
5521
5522 /* top right */
5523 gl_info->gl_ops.gl.p_glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width, 0.0f);
5524 gl_info->gl_ops.gl.p_glVertex2i(fbwidth, fbheight);
5525 gl_info->gl_ops.gl.p_glEnd();
5526 }
5527 gl_info->gl_ops.gl.p_glDisable(texture_target);
5528 checkGLcall("glDisable(texture_target)");
5529
5530 /* Cleanup */
5531 if (src != src_surface->texture_name && src != backup)
5532 {
5533 gl_info->gl_ops.gl.p_glDeleteTextures(1, &src);
5534 checkGLcall("glDeleteTextures(1, &src)");
5535 }
5536 if (backup)
5537 {
5538 gl_info->gl_ops.gl.p_glDeleteTextures(1, &backup);
5539 checkGLcall("glDeleteTextures(1, &backup)");
5540 }
5541
5542 if (wined3d_settings.strict_draw_ordering)
5543 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
5544
5545 context_release(context);
5546
5547 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
5548 * path is never entered
5549 */
5550 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
5551}
5552
5553/* Front buffer coordinates are always full screen coordinates, but our GL
5554 * drawable is limited to the window's client area. The sysmem and texture
5555 * copies do have the full screen size. Note that GL has a bottom-left
5556 * origin, while D3D has a top-left origin. */
5557void surface_translate_drawable_coords(const struct wined3d_surface *surface, HWND window, RECT *rect)
5558{
5559 UINT drawable_height;
5560 if (surface->swapchain && surface == surface->swapchain->front_buffer)
5561 {
5562#ifndef VBOX_WITH_WINE_FIXES
5563 POINT offset = {0, 0};
5564 RECT windowsize;
5565
5566 ScreenToClient(window, &offset);
5567 OffsetRect(rect, offset.x, offset.y);
5568
5569 GetClientRect(window, &windowsize);
5570 drawable_height = windowsize.bottom - windowsize.top;
5571#else
5572# ifdef VBOX_WINE_STRICT
5573 ERR("should not be here!");
5574# else
5575 WARN("should not be here!");
5576# endif
5577 drawable_height = surface->resource.height;
5578#endif
5579 }
5580 else
5581 {
5582 drawable_height = surface->resource.height;
5583 }
5584
5585 rect->top = drawable_height - rect->top;
5586 rect->bottom = drawable_height - rect->bottom;
5587}
5588
5589static void surface_blt_to_drawable(const struct wined3d_device *device,
5590 enum wined3d_texture_filter_type filter, BOOL color_key,
5591 struct wined3d_surface *src_surface, const RECT *src_rect_in,
5592 struct wined3d_surface *dst_surface, const RECT *dst_rect_in)
5593{
5594 const struct wined3d_gl_info *gl_info;
5595 struct wined3d_context *context;
5596 RECT src_rect, dst_rect;
5597
5598 src_rect = *src_rect_in;
5599 dst_rect = *dst_rect_in;
5600
5601 /* Make sure the surface is up-to-date. This should probably use
5602 * surface_load_location() and worry about the destination surface too,
5603 * unless we're overwriting it completely. */
5604 surface_internal_preload(src_surface, SRGB_RGB);
5605
5606 /* Activate the destination context, set it up for blitting */
5607 context = context_acquire(device, dst_surface);
5608 gl_info = context->gl_info;
5609 context_apply_blit_state(context, device);
5610
5611 if (!surface_is_offscreen(dst_surface))
5612#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
5613 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
5614#else
5615 surface_translate_drawable_coords(dst_surface, context->swapchain->win_handle, &dst_rect);
5616#endif
5617
5618 device->blitter->set_shader(device->blit_priv, context, src_surface);
5619
5620 if (color_key)
5621 {
5622 gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST);
5623 checkGLcall("glEnable(GL_ALPHA_TEST)");
5624
5625 /* When the primary render target uses P8, the alpha component
5626 * contains the palette index. Which means that the colorkey is one of
5627 * the palette entries. In other cases pixels that should be masked
5628 * away have alpha set to 0. */
5629 if (primary_render_target_is_p8(device))
5630 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL,
5631 (float)src_surface->src_blt_color_key.color_space_low_value / 256.0f);
5632 else
5633 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL, 0.0f);
5634 checkGLcall("glAlphaFunc");
5635 }
5636 else
5637 {
5638 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
5639 checkGLcall("glDisable(GL_ALPHA_TEST)");
5640 }
5641
5642 draw_textured_quad(src_surface, context, &src_rect, &dst_rect, filter);
5643
5644 if (color_key)
5645 {
5646 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
5647 checkGLcall("glDisable(GL_ALPHA_TEST)");
5648 }
5649
5650 /* Leave the opengl state valid for blitting */
5651 device->blitter->unset_shader(context->gl_info);
5652
5653 if (wined3d_settings.strict_draw_ordering
5654 || (dst_surface->swapchain && dst_surface->swapchain->front_buffer == dst_surface))
5655 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
5656
5657 context_release(context);
5658}
5659
5660/* Do not call while under the GL lock. */
5661HRESULT surface_color_fill(struct wined3d_surface *s, const RECT *rect, const struct wined3d_color *color)
5662{
5663 struct wined3d_device *device = s->resource.device;
5664 const struct blit_shader *blitter;
5665
5666 blitter = wined3d_select_blitter(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_FILL,
5667 NULL, 0, 0, NULL, rect, s->resource.usage, s->resource.pool, s->resource.format);
5668 if (!blitter)
5669 {
5670 FIXME("No blitter is capable of performing the requested color fill operation.\n");
5671 return WINED3DERR_INVALIDCALL;
5672 }
5673
5674 return blitter->color_fill(device, s, rect, color);
5675}
5676
5677/* Do not call while under the GL lock. */
5678static HRESULT IWineD3DSurfaceImpl_BltOverride(struct wined3d_surface *dst_surface, const RECT *dst_rect,
5679 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags, const WINEDDBLTFX *DDBltFx,
5680 enum wined3d_texture_filter_type filter)
5681{
5682 struct wined3d_device *device = dst_surface->resource.device;
5683 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
5684 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
5685
5686 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
5687 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
5688 flags, DDBltFx, debug_d3dtexturefiltertype(filter));
5689
5690 /* Get the swapchain. One of the surfaces has to be a primary surface */
5691 if (dst_surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
5692 {
5693 WARN("Destination is in sysmem, rejecting gl blt\n");
5694 return WINED3DERR_INVALIDCALL;
5695 }
5696
5697 dst_swapchain = dst_surface->swapchain;
5698
5699 if (src_surface)
5700 {
5701 if (src_surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
5702 {
5703 WARN("Src is in sysmem, rejecting gl blt\n");
5704 return WINED3DERR_INVALIDCALL;
5705 }
5706
5707 src_swapchain = src_surface->swapchain;
5708 }
5709 else
5710 {
5711 src_swapchain = NULL;
5712 }
5713
5714 /* Early sort out of cases where no render target is used */
5715 if (!dst_swapchain && !src_swapchain
5716 && src_surface != device->fb.render_targets[0]
5717 && dst_surface != device->fb.render_targets[0])
5718 {
5719 TRACE("No surface is render target, not using hardware blit.\n");
5720 return WINED3DERR_INVALIDCALL;
5721 }
5722
5723 /* No destination color keying supported */
5724 if (flags & (WINEDDBLT_KEYDEST | WINEDDBLT_KEYDESTOVERRIDE))
5725 {
5726 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
5727 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
5728 return WINED3DERR_INVALIDCALL;
5729 }
5730
5731 if (dst_swapchain && dst_swapchain == src_swapchain)
5732 {
5733 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
5734 return WINED3DERR_INVALIDCALL;
5735 }
5736
5737 if (dst_swapchain && src_swapchain)
5738 {
5739 FIXME("Implement hardware blit between two different swapchains\n");
5740 return WINED3DERR_INVALIDCALL;
5741 }
5742
5743 if (dst_swapchain)
5744 {
5745 /* Handled with regular texture -> swapchain blit */
5746 if (src_surface == device->fb.render_targets[0])
5747 TRACE("Blit from active render target to a swapchain\n");
5748 }
5749 else if (src_swapchain && dst_surface == device->fb.render_targets[0])
5750 {
5751 FIXME("Implement blit from a swapchain to the active render target\n");
5752 return WINED3DERR_INVALIDCALL;
5753 }
5754
5755 if ((src_swapchain || src_surface == device->fb.render_targets[0]) && !dst_swapchain)
5756 {
5757 /* Blit from render target to texture */
5758 BOOL stretchx;
5759
5760 /* P8 read back is not implemented */
5761 if (src_surface->resource.format->id == WINED3DFMT_P8_UINT
5762 || dst_surface->resource.format->id == WINED3DFMT_P8_UINT)
5763 {
5764 TRACE("P8 read back not supported by frame buffer to texture blit\n");
5765 return WINED3DERR_INVALIDCALL;
5766 }
5767
5768 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
5769 {
5770 TRACE("Color keying not supported by frame buffer to texture blit\n");
5771 return WINED3DERR_INVALIDCALL;
5772 /* Destination color key is checked above */
5773 }
5774
5775 if (dst_rect->right - dst_rect->left != src_rect->right - src_rect->left)
5776 stretchx = TRUE;
5777 else
5778 stretchx = FALSE;
5779
5780 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
5781 * flip the image nor scale it.
5782 *
5783 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
5784 * -> If the app wants a image width an unscaled width, copy it line per line
5785 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
5786 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
5787 * back buffer. This is slower than reading line per line, thus not used for flipping
5788 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
5789 * pixel by pixel. */
5790 if (!stretchx || dst_rect->right - dst_rect->left > src_surface->resource.width
5791 || dst_rect->bottom - dst_rect->top > src_surface->resource.height)
5792 {
5793 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
5794 fb_copy_to_texture_direct(dst_surface, src_surface, src_rect, dst_rect, filter);
5795 }
5796 else
5797 {
5798 TRACE("Using hardware stretching to flip / stretch the texture.\n");
5799 fb_copy_to_texture_hwstretch(dst_surface, src_surface, src_rect, dst_rect, filter);
5800 }
5801
5802 if (!dst_surface->resource.map_count && !(dst_surface->flags & SFLAG_DONOTFREE))
5803 {
5804 HeapFree(GetProcessHeap(), 0, dst_surface->resource.heapMemory);
5805 dst_surface->resource.allocatedMemory = NULL;
5806 dst_surface->resource.heapMemory = NULL;
5807 }
5808 else
5809 {
5810 dst_surface->flags &= ~SFLAG_INSYSMEM;
5811 }
5812
5813 return WINED3D_OK;
5814 }
5815 else if (src_surface)
5816 {
5817 /* Blit from offscreen surface to render target */
5818 struct wined3d_color_key old_blt_key = src_surface->src_blt_color_key;
5819 DWORD oldCKeyFlags = src_surface->CKeyFlags;
5820
5821 TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface);
5822
5823 if (!device->blitter->blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
5824 src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
5825 dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
5826 {
5827 FIXME("Unsupported blit operation falling back to software\n");
5828 return WINED3DERR_INVALIDCALL;
5829 }
5830
5831 /* Color keying: Check if we have to do a color keyed blt,
5832 * and if not check if a color key is activated.
5833 *
5834 * Just modify the color keying parameters in the surface and restore them afterwards
5835 * The surface keeps track of the color key last used to load the opengl surface.
5836 * PreLoad will catch the change to the flags and color key and reload if necessary.
5837 */
5838 if (flags & WINEDDBLT_KEYSRC)
5839 {
5840 /* Use color key from surface */
5841 }
5842 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
5843 {
5844 /* Use color key from DDBltFx */
5845 src_surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
5846 src_surface->src_blt_color_key = DDBltFx->ddckSrcColorkey;
5847 }
5848 else
5849 {
5850 /* Do not use color key */
5851 src_surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
5852 }
5853
5854 surface_blt_to_drawable(device, filter, flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE),
5855 src_surface, src_rect, dst_surface, dst_rect);
5856
5857 /* Restore the color key parameters */
5858 src_surface->CKeyFlags = oldCKeyFlags;
5859 src_surface->src_blt_color_key = old_blt_key;
5860
5861 surface_modify_location(dst_surface, dst_surface->draw_binding, TRUE);
5862
5863 return WINED3D_OK;
5864 }
5865
5866 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
5867 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
5868 return WINED3DERR_INVALIDCALL;
5869}
5870
5871/* Context activation is done by the caller. */
5872static void surface_depth_blt(const struct wined3d_surface *surface, struct wined3d_context *context,
5873 GLuint texture, GLint x, GLint y, GLsizei w, GLsizei h, GLenum target)
5874{
5875 struct wined3d_device *device = surface->resource.device;
5876 const struct wined3d_gl_info *gl_info = context->gl_info;
5877 GLint compare_mode = GL_NONE;
5878 struct blt_info info;
5879 GLint old_binding = 0;
5880 RECT rect;
5881
5882 gl_info->gl_ops.gl.p_glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
5883
5884 gl_info->gl_ops.gl.p_glDisable(GL_CULL_FACE);
5885 gl_info->gl_ops.gl.p_glDisable(GL_BLEND);
5886 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
5887 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
5888 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST);
5889 gl_info->gl_ops.gl.p_glEnable(GL_DEPTH_TEST);
5890 gl_info->gl_ops.gl.p_glDepthFunc(GL_ALWAYS);
5891 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
5892 gl_info->gl_ops.gl.p_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
5893 gl_info->gl_ops.gl.p_glViewport(x, y, w, h);
5894 gl_info->gl_ops.gl.p_glDepthRange(0.0, 1.0);
5895
5896 SetRect(&rect, 0, h, w, 0);
5897 surface_get_blt_info(target, &rect, surface->pow2Width, surface->pow2Height, &info);
5898 context_active_texture(context, context->gl_info, 0);
5899 gl_info->gl_ops.gl.p_glGetIntegerv(info.binding, &old_binding);
5900 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, texture);
5901 if (gl_info->supported[ARB_SHADOW])
5902 {
5903 gl_info->gl_ops.gl.p_glGetTexParameteriv(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, &compare_mode);
5904 if (compare_mode != GL_NONE)
5905 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
5906 }
5907
5908 device->shader_backend->shader_select_depth_blt(device->shader_priv,
5909 gl_info, info.tex_type, &surface->ds_current_size);
5910
5911 gl_info->gl_ops.gl.p_glBegin(GL_TRIANGLE_STRIP);
5912 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[0]);
5913 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, -1.0f);
5914 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[1]);
5915 gl_info->gl_ops.gl.p_glVertex2f(1.0f, -1.0f);
5916 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[2]);
5917 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, 1.0f);
5918 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[3]);
5919 gl_info->gl_ops.gl.p_glVertex2f(1.0f, 1.0f);
5920 gl_info->gl_ops.gl.p_glEnd();
5921
5922 if (compare_mode != GL_NONE)
5923 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, compare_mode);
5924 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, old_binding);
5925
5926 gl_info->gl_ops.gl.p_glPopAttrib();
5927
5928 device->shader_backend->shader_deselect_depth_blt(device->shader_priv, gl_info);
5929}
5930
5931void surface_modify_ds_location(struct wined3d_surface *surface,
5932 DWORD location, UINT w, UINT h)
5933{
5934 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface, location, w, h);
5935
5936 if (location & ~(SFLAG_LOCATIONS | SFLAG_DISCARDED))
5937 FIXME("Invalid location (%#x) specified.\n", location);
5938
5939 if (((surface->flags & SFLAG_INTEXTURE) && !(location & SFLAG_INTEXTURE))
5940 || (!(surface->flags & SFLAG_INTEXTURE) && (location & SFLAG_INTEXTURE)))
5941 {
5942 if (surface->container)
5943 {
5944 TRACE("Passing to container.\n");
5945 wined3d_texture_set_dirty(surface->container, TRUE);
5946 }
5947 }
5948
5949 surface->ds_current_size.cx = w;
5950 surface->ds_current_size.cy = h;
5951 surface->flags &= ~(SFLAG_LOCATIONS | SFLAG_DISCARDED);
5952 surface->flags |= location;
5953}
5954
5955/* Context activation is done by the caller. */
5956void surface_load_ds_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
5957{
5958 const struct wined3d_gl_info *gl_info = context->gl_info;
5959 struct wined3d_device *device = surface->resource.device;
5960 GLsizei w, h;
5961
5962 TRACE("surface %p, new location %#x.\n", surface, location);
5963
5964 /* TODO: Make this work for modes other than FBO */
5965 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
5966
5967 if (!(surface->flags & location))
5968 {
5969 w = surface->ds_current_size.cx;
5970 h = surface->ds_current_size.cy;
5971 surface->ds_current_size.cx = 0;
5972 surface->ds_current_size.cy = 0;
5973 }
5974 else
5975 {
5976 w = surface->resource.width;
5977 h = surface->resource.height;
5978 }
5979
5980 if (surface->ds_current_size.cx == surface->resource.width
5981 && surface->ds_current_size.cy == surface->resource.height)
5982 {
5983 TRACE("Location (%#x) is already up to date.\n", location);
5984 return;
5985 }
5986
5987 if (surface->current_renderbuffer)
5988 {
5989 FIXME("Not supported with fixed up depth stencil.\n");
5990 return;
5991 }
5992
5993 if (surface->flags & SFLAG_DISCARDED)
5994 {
5995 TRACE("Surface was discarded, no need copy data.\n");
5996 switch (location)
5997 {
5998 case SFLAG_INTEXTURE:
5999 surface_prepare_texture(surface, context, FALSE);
6000 break;
6001 case SFLAG_INRB_MULTISAMPLE:
6002 surface_prepare_rb(surface, gl_info, TRUE);
6003 break;
6004 case SFLAG_INDRAWABLE:
6005 /* Nothing to do */
6006 break;
6007 default:
6008 FIXME("Unhandled location %#x\n", location);
6009 }
6010 surface->flags &= ~SFLAG_DISCARDED;
6011 surface->flags |= location;
6012 surface->ds_current_size.cx = surface->resource.width;
6013 surface->ds_current_size.cy = surface->resource.height;
6014 return;
6015 }
6016
6017 if (!(surface->flags & SFLAG_LOCATIONS))
6018 {
6019 FIXME("No up to date depth stencil location.\n");
6020 surface->flags |= location;
6021 surface->ds_current_size.cx = surface->resource.width;
6022 surface->ds_current_size.cy = surface->resource.height;
6023 return;
6024 }
6025
6026 if (location == SFLAG_INTEXTURE)
6027 {
6028 GLint old_binding = 0;
6029 GLenum bind_target;
6030
6031 /* The render target is allowed to be smaller than the depth/stencil
6032 * buffer, so the onscreen depth/stencil buffer is potentially smaller
6033 * than the offscreen surface. Don't overwrite the offscreen surface
6034 * with undefined data. */
6035 w = min(w, context->swapchain->desc.backbuffer_width);
6036 h = min(h, context->swapchain->desc.backbuffer_height);
6037
6038 TRACE("Copying onscreen depth buffer to depth texture.\n");
6039
6040 if (!device->depth_blt_texture)
6041 gl_info->gl_ops.gl.p_glGenTextures(1, &device->depth_blt_texture);
6042
6043 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
6044 * directly on the FBO texture. That's because we need to flip. */
6045 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
6046 context->swapchain->front_buffer, NULL, SFLAG_INDRAWABLE);
6047 if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
6048 {
6049 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6050 bind_target = GL_TEXTURE_RECTANGLE_ARB;
6051 }
6052 else
6053 {
6054 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6055 bind_target = GL_TEXTURE_2D;
6056 }
6057 gl_info->gl_ops.gl.p_glBindTexture(bind_target, device->depth_blt_texture);
6058 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
6059 * internal format, because the internal format might include stencil
6060 * data. In principle we should copy stencil data as well, but unless
6061 * the driver supports stencil export it's hard to do, and doesn't
6062 * seem to be needed in practice. If the hardware doesn't support
6063 * writing stencil data, the glCopyTexImage2D() call might trigger
6064 * software fallbacks. */
6065 gl_info->gl_ops.gl.p_glCopyTexImage2D(bind_target, 0, GL_DEPTH_COMPONENT, 0, 0, w, h, 0);
6066 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6067 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6068 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
6069 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
6070 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
6071 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6072 gl_info->gl_ops.gl.p_glBindTexture(bind_target, old_binding);
6073
6074 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
6075 NULL, surface, SFLAG_INTEXTURE);
6076 context_set_draw_buffer(context, GL_NONE);
6077
6078 /* Do the actual blit */
6079 surface_depth_blt(surface, context, device->depth_blt_texture, 0, 0, w, h, bind_target);
6080 checkGLcall("depth_blt");
6081
6082 context_invalidate_state(context, STATE_FRAMEBUFFER);
6083
6084 if (wined3d_settings.strict_draw_ordering)
6085 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
6086 }
6087 else if (location == SFLAG_INDRAWABLE)
6088 {
6089 TRACE("Copying depth texture to onscreen depth buffer.\n");
6090
6091 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
6092 context->swapchain->front_buffer, NULL, SFLAG_INDRAWABLE);
6093 surface_depth_blt(surface, context, surface->texture_name,
6094 0, surface->pow2Height - h, w, h, surface->texture_target);
6095 checkGLcall("depth_blt");
6096
6097 context_invalidate_state(context, STATE_FRAMEBUFFER);
6098
6099 if (wined3d_settings.strict_draw_ordering)
6100 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
6101 }
6102 else
6103 {
6104 ERR("Invalid location (%#x) specified.\n", location);
6105 }
6106
6107 surface->flags |= location;
6108 surface->ds_current_size.cx = surface->resource.width;
6109 surface->ds_current_size.cy = surface->resource.height;
6110}
6111
6112void surface_modify_location(struct wined3d_surface *surface, DWORD location, BOOL persistent)
6113{
6114 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
6115 struct wined3d_surface *overlay;
6116
6117 TRACE("surface %p, location %s, persistent %#x.\n",
6118 surface, debug_surflocation(location), persistent);
6119
6120 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && surface_is_offscreen(surface)
6121 && !(surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
6122 && (location & SFLAG_INDRAWABLE))
6123 ERR("Trying to invalidate the SFLAG_INDRAWABLE location of an offscreen surface.\n");
6124
6125 if (location & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)
6126 && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6127 location |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX);
6128
6129 if (persistent)
6130 {
6131 if (((surface->flags & SFLAG_INTEXTURE) && !(location & SFLAG_INTEXTURE))
6132 || ((surface->flags & SFLAG_INSRGBTEX) && !(location & SFLAG_INSRGBTEX)))
6133 {
6134 if (surface->container)
6135 {
6136 TRACE("Passing to container.\n");
6137 wined3d_texture_set_dirty(surface->container, TRUE);
6138 }
6139 }
6140
6141#ifdef VBOX_WITH_WDDM
6142 {
6143 /* sometimes wine can call ModifyLocation(SFLAG_INTEXTURE, TRUE) for surfaces that do not yet have
6144 * ogl texture backend assigned, e.g. when doing ColorFill right after surface creation
6145 * to prevent wine state breakage that could occur later on in that case, we check
6146 * whether tex gen is needed here and generate it accordingly */
6147 if (!surface->texture_name)
6148 {
6149 Assert(!(surface->flags & SFLAG_INTEXTURE));
6150 if (location & SFLAG_INTEXTURE)
6151 {
6152 Assert(0);
6153// struct wined3d_context *context = NULL;
6154// IWineD3DDeviceImpl *device = This->resource.device;
6155// const struct wined3d_gl_info *gl_info;
6156//
6157// if (!device->isInDraw) context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6158// gl_info = context->gl_info;
6159//
6160// surface_prepare_texture(This, gl_info, FALSE);
6161//
6162// if (context) context_release(context);
6163 }
6164 }
6165
6166 if (!surface->texture_name_srgb)
6167 {
6168 Assert(!(surface->flags & SFLAG_INSRGBTEX));
6169 if (location & SFLAG_INSRGBTEX)
6170 {
6171 Assert(0);
6172// struct wined3d_context *context = NULL;
6173// IWineD3DDeviceImpl *device = This->resource.device;
6174// const struct wined3d_gl_info *gl_info;
6175//
6176// if (!device->isInDraw) context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6177// gl_info = context->gl_info;
6178//
6179// surface_prepare_texture(This, gl_info, TRUE);
6180//
6181// if (context) context_release(context);
6182 }
6183 }
6184 }
6185#endif
6186
6187 surface->flags &= ~SFLAG_LOCATIONS;
6188 surface->flags |= location;
6189
6190 /* Redraw emulated overlays, if any */
6191 if (location & SFLAG_INDRAWABLE && !list_empty(&surface->overlays))
6192 {
6193 LIST_FOR_EACH_ENTRY(overlay, &surface->overlays, struct wined3d_surface, overlay_entry)
6194 {
6195 surface_draw_overlay(overlay);
6196 }
6197 }
6198 }
6199 else
6200 {
6201 if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) && (location & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)))
6202 {
6203 if (surface->container)
6204 {
6205 TRACE("Passing to container\n");
6206 wined3d_texture_set_dirty(surface->container, TRUE);
6207 }
6208 }
6209 surface->flags &= ~location;
6210 }
6211
6212#ifdef VBOX_WITH_WDDM
6213 if(VBOXSHRC_IS_SHARED_UNLOCKED(surface)) {
6214 /* with the shared resource only texture can be considered valid
6215 * to make sure changes done to the resource in the other device context are visible
6216 * because the resource contents is shared via texture.
6217 * This is why we ensure texture location is the one and only which is always valid */
6218 if(!(surface->flags & SFLAG_INTEXTURE)) {
6219 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
6220 } else {
6221 surface->flags &= ~SFLAG_LOCATIONS;
6222 surface->flags |= SFLAG_INTEXTURE;
6223 }
6224 }
6225 else if (surface->flags & SFLAG_CLIENTMEM)
6226 {
6227 if(!(surface->flags & SFLAG_INSYSMEM)) {
6228 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
6229 } else {
6230 surface->flags &= ~SFLAG_LOCATIONS;
6231 surface->flags |= SFLAG_INSYSMEM;
6232 }
6233 }
6234#endif
6235
6236
6237 if (!(surface->flags & SFLAG_LOCATIONS))
6238 {
6239 ERR("Surface %p does not have any up to date location.\n", surface);
6240 }
6241}
6242
6243static DWORD resource_access_from_location(DWORD location)
6244{
6245 switch (location)
6246 {
6247 case SFLAG_INSYSMEM:
6248 return WINED3D_RESOURCE_ACCESS_CPU;
6249
6250 case SFLAG_INDRAWABLE:
6251 case SFLAG_INSRGBTEX:
6252 case SFLAG_INTEXTURE:
6253 case SFLAG_INRB_MULTISAMPLE:
6254 case SFLAG_INRB_RESOLVED:
6255 return WINED3D_RESOURCE_ACCESS_GPU;
6256
6257 default:
6258 FIXME("Unhandled location %#x.\n", location);
6259 return 0;
6260 }
6261}
6262
6263static void surface_load_sysmem(struct wined3d_surface *surface,
6264 const struct wined3d_gl_info *gl_info, const RECT *rect)
6265{
6266 surface_prepare_system_memory(surface);
6267
6268 if (surface->flags & (SFLAG_INRB_MULTISAMPLE | SFLAG_INRB_RESOLVED))
6269 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
6270
6271 /* Download the surface to system memory. */
6272 if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX))
6273 {
6274 struct wined3d_device *device = surface->resource.device;
6275 struct wined3d_context *context;
6276
6277 /* TODO: Use already acquired context when possible. */
6278 context = context_acquire(device, NULL);
6279
6280 surface_bind_and_dirtify(surface, context, !(surface->flags & SFLAG_INTEXTURE));
6281 surface_download_data(surface, gl_info);
6282
6283 context_release(context);
6284
6285 return;
6286 }
6287
6288 if (surface->flags & SFLAG_INDRAWABLE)
6289 {
6290 read_from_framebuffer(surface, rect, surface->resource.allocatedMemory,
6291 wined3d_surface_get_pitch(surface));
6292 return;
6293 }
6294
6295 FIXME("Can't load surface %p with location flags %#x into sysmem.\n",
6296 surface, surface->flags & SFLAG_LOCATIONS);
6297}
6298
6299static HRESULT surface_load_drawable(struct wined3d_surface *surface,
6300 const struct wined3d_gl_info *gl_info, const RECT *rect)
6301{
6302 struct wined3d_device *device = surface->resource.device;
6303 enum wined3d_conversion_type convert;
6304 struct wined3d_format format;
6305 UINT byte_count;
6306 BYTE *mem;
6307
6308 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && surface_is_offscreen(surface))
6309 {
6310 ERR("Trying to load offscreen surface into SFLAG_INDRAWABLE.\n");
6311 return WINED3DERR_INVALIDCALL;
6312 }
6313
6314 if (wined3d_settings.rendertargetlock_mode == RTL_READTEX)
6315 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
6316
6317 if (surface->flags & SFLAG_INTEXTURE)
6318 {
6319 RECT r;
6320
6321 surface_get_rect(surface, rect, &r);
6322 surface_blt_to_drawable(device, WINED3D_TEXF_POINT, FALSE, surface, &r, surface, &r);
6323
6324 return WINED3D_OK;
6325 }
6326
6327 if ((surface->flags & SFLAG_LOCATIONS) == SFLAG_INSRGBTEX)
6328 {
6329 /* This needs colorspace conversion from sRGB to RGB. We take the slow
6330 * path through sysmem. */
6331 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6332 }
6333
6334 d3dfmt_get_conv(surface, FALSE, FALSE, &format, &convert);
6335
6336 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
6337 * SFLAG_CONVERTED but it isn't set (yet) in all cases where it is getting
6338 * called. */
6339 if ((convert != WINED3D_CT_NONE) && (surface->flags & SFLAG_PBO))
6340 {
6341 struct wined3d_context *context;
6342
6343 TRACE("Removing the pbo attached to surface %p.\n", surface);
6344
6345 /* TODO: Use already acquired context when possible. */
6346 context = context_acquire(device, NULL);
6347
6348 surface_remove_pbo(surface, gl_info);
6349
6350 context_release(context);
6351 }
6352
6353 if ((convert != WINED3D_CT_NONE) && surface->resource.allocatedMemory)
6354 {
6355 UINT height = surface->resource.height;
6356 UINT width = surface->resource.width;
6357 UINT src_pitch, dst_pitch;
6358
6359 byte_count = format.conv_byte_count;
6360 src_pitch = wined3d_surface_get_pitch(surface);
6361
6362 /* Stick to the alignment for the converted surface too, makes it
6363 * easier to load the surface. */
6364 dst_pitch = width * byte_count;
6365 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6366
6367 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
6368 {
6369 ERR("Out of memory (%u).\n", dst_pitch * height);
6370 return E_OUTOFMEMORY;
6371 }
6372
6373 d3dfmt_convert_surface(surface->resource.allocatedMemory, mem,
6374 src_pitch, width, height, dst_pitch, convert, surface);
6375
6376 surface->flags |= SFLAG_CONVERTED;
6377 }
6378 else
6379 {
6380 surface->flags &= ~SFLAG_CONVERTED;
6381 mem = surface->resource.allocatedMemory;
6382 byte_count = format.byte_count;
6383 }
6384
6385 flush_to_framebuffer_drawpixels(surface, rect, format.glFormat, format.glType, byte_count, mem);
6386
6387 /* Don't delete PBO memory. */
6388 if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO))
6389 HeapFree(GetProcessHeap(), 0, mem);
6390
6391 return WINED3D_OK;
6392}
6393
6394static HRESULT surface_load_texture(struct wined3d_surface *surface,
6395 const struct wined3d_gl_info *gl_info, const RECT *rect, BOOL srgb)
6396{
6397 RECT src_rect = {0, 0, surface->resource.width, surface->resource.height};
6398 struct wined3d_device *device = surface->resource.device;
6399 enum wined3d_conversion_type convert;
6400 struct wined3d_context *context;
6401 UINT width, src_pitch, dst_pitch;
6402 struct wined3d_bo_address data;
6403 struct wined3d_format format;
6404 POINT dst_point = {0, 0};
6405 BYTE *mem;
6406
6407 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
6408 && surface_is_offscreen(surface)
6409 && (surface->flags & SFLAG_INDRAWABLE))
6410 {
6411 surface_load_fb_texture(surface, srgb);
6412
6413 return WINED3D_OK;
6414 }
6415
6416 if (surface->flags & (SFLAG_INSRGBTEX | SFLAG_INTEXTURE)
6417 && (surface->resource.format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)
6418 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
6419 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
6420 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
6421 {
6422 if (srgb)
6423 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, SFLAG_INTEXTURE,
6424 &src_rect, surface, SFLAG_INSRGBTEX, &src_rect);
6425 else
6426 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, SFLAG_INSRGBTEX,
6427 &src_rect, surface, SFLAG_INTEXTURE, &src_rect);
6428
6429 return WINED3D_OK;
6430 }
6431
6432 if (surface->flags & (SFLAG_INRB_MULTISAMPLE | SFLAG_INRB_RESOLVED)
6433 && (!srgb || (surface->resource.format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB))
6434 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
6435 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
6436 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
6437 {
6438 DWORD src_location = surface->flags & SFLAG_INRB_RESOLVED ? SFLAG_INRB_RESOLVED : SFLAG_INRB_MULTISAMPLE;
6439 DWORD dst_location = srgb ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
6440 RECT rect = {0, 0, surface->resource.width, surface->resource.height};
6441
6442 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, src_location,
6443 &rect, surface, dst_location, &rect);
6444
6445 return WINED3D_OK;
6446 }
6447
6448 /* Upload from system memory */
6449
6450 d3dfmt_get_conv(surface, TRUE /* We need color keying */,
6451 TRUE /* We will use textures */, &format, &convert);
6452
6453 if (srgb)
6454 {
6455 if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSYSMEM)) == SFLAG_INTEXTURE)
6456 {
6457 /* Performance warning... */
6458 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface);
6459 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6460 }
6461 }
6462 else
6463 {
6464 if ((surface->flags & (SFLAG_INSRGBTEX | SFLAG_INSYSMEM)) == SFLAG_INSRGBTEX)
6465 {
6466 /* Performance warning... */
6467 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface);
6468 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6469 }
6470 }
6471
6472 if (!(surface->flags & SFLAG_INSYSMEM))
6473 {
6474 WARN("Trying to load a texture from sysmem, but SFLAG_INSYSMEM is not set.\n");
6475 /* Lets hope we get it from somewhere... */
6476 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6477 }
6478
6479 /* TODO: Use already acquired context when possible. */
6480 context = context_acquire(device, NULL);
6481
6482 surface_prepare_texture(surface, context, srgb);
6483 surface_bind_and_dirtify(surface, context, srgb);
6484
6485 if (surface->CKeyFlags & WINEDDSD_CKSRCBLT)
6486 {
6487 surface->flags |= SFLAG_GLCKEY;
6488 surface->gl_color_key = surface->src_blt_color_key;
6489 }
6490 else surface->flags &= ~SFLAG_GLCKEY;
6491
6492 width = surface->resource.width;
6493 src_pitch = wined3d_surface_get_pitch(surface);
6494
6495 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
6496 * SFLAG_CONVERTED but it isn't set (yet) in all cases it is getting
6497 * called. */
6498 if ((convert != WINED3D_CT_NONE || format.convert) && (surface->flags & SFLAG_PBO))
6499 {
6500 TRACE("Removing the pbo attached to surface %p.\n", surface);
6501 surface_remove_pbo(surface, gl_info);
6502 }
6503
6504 if (format.convert)
6505 {
6506 /* This code is entered for texture formats which need a fixup. */
6507 UINT height = surface->resource.height;
6508
6509 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6510 dst_pitch = width * format.conv_byte_count;
6511 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6512
6513 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
6514 {
6515 ERR("Out of memory (%u).\n", dst_pitch * height);
6516 context_release(context);
6517 return E_OUTOFMEMORY;
6518 }
6519 format.convert(surface->resource.allocatedMemory, mem, src_pitch, width, height);
6520 format.byte_count = format.conv_byte_count;
6521 src_pitch = dst_pitch;
6522 }
6523 else if (convert != WINED3D_CT_NONE && surface->resource.allocatedMemory)
6524 {
6525 /* This code is only entered for color keying fixups */
6526 UINT height = surface->resource.height;
6527
6528 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6529 dst_pitch = width * format.conv_byte_count;
6530 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6531
6532 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
6533 {
6534 ERR("Out of memory (%u).\n", dst_pitch * height);
6535 context_release(context);
6536 return E_OUTOFMEMORY;
6537 }
6538 d3dfmt_convert_surface(surface->resource.allocatedMemory, mem, src_pitch,
6539 width, height, dst_pitch, convert, surface);
6540 format.byte_count = format.conv_byte_count;
6541 src_pitch = dst_pitch;
6542 }
6543 else
6544 {
6545 mem = surface->resource.allocatedMemory;
6546 }
6547
6548 data.buffer_object = surface->pbo;
6549 data.addr = mem;
6550 surface_upload_data(surface, gl_info, &format, &src_rect, src_pitch, &dst_point, srgb, &data);
6551
6552 context_release(context);
6553
6554 /* Don't delete PBO memory. */
6555 if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO))
6556 HeapFree(GetProcessHeap(), 0, mem);
6557
6558 return WINED3D_OK;
6559}
6560
6561static void surface_multisample_resolve(struct wined3d_surface *surface)
6562{
6563 RECT rect = {0, 0, surface->resource.width, surface->resource.height};
6564
6565 if (!(surface->flags & SFLAG_INRB_MULTISAMPLE))
6566 ERR("Trying to resolve multisampled surface %p, but location SFLAG_INRB_MULTISAMPLE not current.\n", surface);
6567
6568 surface_blt_fbo(surface->resource.device, WINED3D_TEXF_POINT,
6569 surface, SFLAG_INRB_MULTISAMPLE, &rect, surface, SFLAG_INRB_RESOLVED, &rect);
6570}
6571
6572HRESULT surface_load_location(struct wined3d_surface *surface, DWORD location, const RECT *rect)
6573{
6574 struct wined3d_device *device = surface->resource.device;
6575 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6576 HRESULT hr;
6577
6578 TRACE("surface %p, location %s, rect %s.\n", surface, debug_surflocation(location), wine_dbgstr_rect(rect));
6579
6580 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
6581 {
6582 if (location == SFLAG_INTEXTURE && surface->flags & SFLAG_INDRAWABLE)
6583 {
6584 struct wined3d_context *context = context_acquire(device, NULL);
6585 surface_load_ds_location(surface, context, location);
6586 context_release(context);
6587#ifndef VBOX_WITH_WDDM
6588 return WINED3D_OK;
6589#else
6590 goto post_process;
6591#endif
6592 }
6593 else if (location & surface->flags && surface->draw_binding != SFLAG_INDRAWABLE)
6594 {
6595 /* Already up to date, nothing to do. */
6596#ifndef VBOX_WITH_WDDM
6597 return WINED3D_OK;
6598#else
6599 goto post_process;
6600#endif
6601 }
6602 else
6603 {
6604 FIXME("Unimplemented copy from %s to %s for depth/stencil buffers.\n",
6605 debug_surflocation(surface->flags & SFLAG_LOCATIONS), debug_surflocation(location));
6606 return WINED3DERR_INVALIDCALL;
6607 }
6608 }
6609
6610 if (location == SFLAG_INSRGBTEX && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6611 location = SFLAG_INTEXTURE;
6612
6613 if (surface->flags & location)
6614 {
6615 TRACE("Location already up to date.\n");
6616
6617 if (location == SFLAG_INSYSMEM && !(surface->flags & SFLAG_PBO)
6618 && surface_need_pbo(surface, gl_info))
6619 surface_load_pbo(surface, gl_info);
6620
6621#ifndef VBOX_WITH_WDDM
6622 return WINED3D_OK;
6623#else
6624 goto post_process;
6625#endif
6626 }
6627
6628 if (WARN_ON(d3d_surface))
6629 {
6630 DWORD required_access = resource_access_from_location(location);
6631 if ((surface->resource.access_flags & required_access) != required_access)
6632 WARN("Operation requires %#x access, but surface only has %#x.\n",
6633 required_access, surface->resource.access_flags);
6634 }
6635
6636 if (!(surface->flags & SFLAG_LOCATIONS))
6637 {
6638 ERR("Surface %p does not have any up to date location.\n", surface);
6639 surface->flags |= SFLAG_LOST;
6640 return WINED3DERR_DEVICELOST;
6641 }
6642
6643 switch (location)
6644 {
6645 case SFLAG_INSYSMEM:
6646 surface_load_sysmem(surface, gl_info, rect);
6647 break;
6648
6649 case SFLAG_INDRAWABLE:
6650 if (FAILED(hr = surface_load_drawable(surface, gl_info, rect)))
6651 return hr;
6652 break;
6653
6654 case SFLAG_INRB_RESOLVED:
6655 surface_multisample_resolve(surface);
6656 break;
6657
6658 case SFLAG_INTEXTURE:
6659 case SFLAG_INSRGBTEX:
6660 if (FAILED(hr = surface_load_texture(surface, gl_info, rect, location == SFLAG_INSRGBTEX)))
6661 return hr;
6662 break;
6663
6664 default:
6665 ERR("Don't know how to handle location %#x.\n", location);
6666 break;
6667 }
6668
6669#ifdef VBOX_WITH_WDDM
6670post_process:
6671
6672 if (VBOXSHRC_IS_SHARED_UNLOCKED(surface))
6673 {
6674 /* with the shared resource only texture can be considered valid
6675 * to make sure changes done to the resource in the other device context are visible
6676 * because the resource contents is shared via texture.
6677 * One can load and use other locations as needed,
6678 * but they should be reloaded each time on each usage */
6679 Assert(!!(surface->flags & SFLAG_INTEXTURE) || !!(location & SFLAG_INTEXTURE));
6680 surface->flags &= ~SFLAG_LOCATIONS;
6681 surface->flags |= SFLAG_INTEXTURE;
6682 /* @todo: SFLAG_INSRGBTEX ?? */
6683// if (in_fbo)
6684// {
6685// surface->flags |= SFLAG_INDRAWABLE;
6686// }
6687 }
6688 else if (surface->flags & SFLAG_CLIENTMEM)
6689 {
6690 Assert(!!(surface->flags & SFLAG_INSYSMEM));
6691 surface->flags &= ~SFLAG_LOCATIONS;
6692 surface->flags |= SFLAG_INSYSMEM;
6693 }
6694 else
6695#endif
6696 {
6697 if (!rect)
6698 {
6699 surface->flags |= location;
6700
6701 if (location != SFLAG_INSYSMEM && (surface->flags & SFLAG_INSYSMEM))
6702 surface_evict_sysmem(surface);
6703 }
6704
6705 if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)
6706 && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6707 {
6708 surface->flags |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX);
6709 }
6710 }
6711
6712 return WINED3D_OK;
6713}
6714
6715BOOL surface_is_offscreen(const struct wined3d_surface *surface)
6716{
6717 struct wined3d_swapchain *swapchain;
6718
6719 /* Not on a swapchain - must be offscreen */
6720 if (!(swapchain = surface->swapchain))
6721 return TRUE;
6722
6723 /* The front buffer is always onscreen */
6724 if (surface == swapchain->front_buffer) return FALSE;
6725
6726 /* If the swapchain is rendered to an FBO, the backbuffer is
6727 * offscreen, otherwise onscreen */
6728 return swapchain->render_to_fbo;
6729}
6730
6731static HRESULT ffp_blit_alloc(struct wined3d_device *device) { return WINED3D_OK; }
6732/* Context activation is done by the caller. */
6733static void ffp_blit_free(struct wined3d_device *device) { }
6734
6735/* This function is used in case of 8bit paletted textures using GL_EXT_paletted_texture */
6736/* Context activation is done by the caller. */
6737static void ffp_blit_p8_upload_palette(const struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
6738{
6739 BYTE table[256][4];
6740 BOOL colorkey_active = (surface->CKeyFlags & WINEDDSD_CKSRCBLT) != 0;
6741 GLenum target;
6742
6743 if (surface->container)
6744 target = surface->container->target;
6745 else
6746 target = surface->texture_target;
6747
6748 d3dfmt_p8_init_palette(surface, table, colorkey_active);
6749
6750 TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n");
6751 GL_EXTCALL(glColorTableEXT(target, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, table));
6752}
6753
6754/* Context activation is done by the caller. */
6755static HRESULT ffp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
6756{
6757 enum complex_fixup fixup = get_complex_fixup(surface->resource.format->color_fixup);
6758 const struct wined3d_gl_info *gl_info = context->gl_info;
6759 GLenum target;
6760
6761 if (surface->container)
6762 target = surface->container->target;
6763 else
6764 target = surface->texture_target;
6765
6766 /* When EXT_PALETTED_TEXTURE is around, palette conversion is done by the GPU
6767 * else the surface is converted in software at upload time in LoadLocation.
6768 */
6769 if (!(surface->flags & SFLAG_CONVERTED) && fixup == COMPLEX_FIXUP_P8
6770 && gl_info->supported[EXT_PALETTED_TEXTURE])
6771 ffp_blit_p8_upload_palette(surface, gl_info);
6772
6773 gl_info->gl_ops.gl.p_glEnable(target);
6774 checkGLcall("glEnable(target)");
6775 return WINED3D_OK;
6776}
6777
6778/* Context activation is done by the caller. */
6779static void ffp_blit_unset(const struct wined3d_gl_info *gl_info)
6780{
6781 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
6782 checkGLcall("glDisable(GL_TEXTURE_2D)");
6783 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
6784 {
6785 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
6786 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
6787 }
6788 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
6789 {
6790 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
6791 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
6792 }
6793}
6794
6795static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
6796 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
6797 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
6798{
6799 enum complex_fixup src_fixup;
6800
6801 switch (blit_op)
6802 {
6803 case WINED3D_BLIT_OP_COLOR_BLIT:
6804 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
6805 return FALSE;
6806
6807 src_fixup = get_complex_fixup(src_format->color_fixup);
6808 if (TRACE_ON(d3d_surface) && TRACE_ON(d3d))
6809 {
6810 TRACE("Checking support for fixup:\n");
6811 dump_color_fixup_desc(src_format->color_fixup);
6812 }
6813
6814 if (!is_identity_fixup(dst_format->color_fixup))
6815 {
6816 TRACE("Destination fixups are not supported\n");
6817 return FALSE;
6818 }
6819
6820 if (src_fixup == COMPLEX_FIXUP_P8 && gl_info->supported[EXT_PALETTED_TEXTURE])
6821 {
6822 TRACE("P8 fixup supported\n");
6823 return TRUE;
6824 }
6825
6826 /* We only support identity conversions. */
6827 if (is_identity_fixup(src_format->color_fixup))
6828 {
6829 TRACE("[OK]\n");
6830 return TRUE;
6831 }
6832
6833 TRACE("[FAILED]\n");
6834 return FALSE;
6835
6836 case WINED3D_BLIT_OP_COLOR_FILL:
6837 if (dst_pool == WINED3D_POOL_SYSTEM_MEM)
6838 return FALSE;
6839
6840 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6841 {
6842 if (!((dst_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
6843 return FALSE;
6844 }
6845 else if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
6846 {
6847 TRACE("Color fill not supported\n");
6848 return FALSE;
6849 }
6850
6851 /* FIXME: We should reject color fills on formats with fixups,
6852 * but this would break P8 color fills for example. */
6853
6854 return TRUE;
6855
6856 case WINED3D_BLIT_OP_DEPTH_FILL:
6857 return TRUE;
6858
6859 default:
6860 TRACE("Unsupported blit_op=%d\n", blit_op);
6861 return FALSE;
6862 }
6863}
6864
6865/* Do not call while under the GL lock. */
6866static HRESULT ffp_blit_color_fill(struct wined3d_device *device, struct wined3d_surface *dst_surface,
6867 const RECT *dst_rect, const struct wined3d_color *color)
6868{
6869 const RECT draw_rect = {0, 0, dst_surface->resource.width, dst_surface->resource.height};
6870 struct wined3d_fb_state fb = {&dst_surface, NULL};
6871
6872 device_clear_render_targets(device, 1, &fb, 1, dst_rect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
6873
6874 return WINED3D_OK;
6875}
6876
6877/* Do not call while under the GL lock. */
6878static HRESULT ffp_blit_depth_fill(struct wined3d_device *device,
6879 struct wined3d_surface *surface, const RECT *rect, float depth)
6880{
6881 const RECT draw_rect = {0, 0, surface->resource.width, surface->resource.height};
6882 struct wined3d_fb_state fb = {NULL, surface};
6883
6884 device_clear_render_targets(device, 0, &fb, 1, rect, &draw_rect, WINED3DCLEAR_ZBUFFER, 0, depth, 0);
6885
6886 return WINED3D_OK;
6887}
6888
6889const struct blit_shader ffp_blit = {
6890 ffp_blit_alloc,
6891 ffp_blit_free,
6892 ffp_blit_set,
6893 ffp_blit_unset,
6894 ffp_blit_supported,
6895 ffp_blit_color_fill,
6896 ffp_blit_depth_fill,
6897};
6898
6899static HRESULT cpu_blit_alloc(struct wined3d_device *device)
6900{
6901 return WINED3D_OK;
6902}
6903
6904/* Context activation is done by the caller. */
6905static void cpu_blit_free(struct wined3d_device *device)
6906{
6907}
6908
6909/* Context activation is done by the caller. */
6910static HRESULT cpu_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
6911{
6912 return WINED3D_OK;
6913}
6914
6915/* Context activation is done by the caller. */
6916static void cpu_blit_unset(const struct wined3d_gl_info *gl_info)
6917{
6918}
6919
6920static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
6921 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
6922 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
6923{
6924 if (blit_op == WINED3D_BLIT_OP_COLOR_FILL)
6925 {
6926 return TRUE;
6927 }
6928
6929 return FALSE;
6930}
6931
6932static HRESULT surface_cpu_blt_compressed(const BYTE *src_data, BYTE *dst_data,
6933 UINT src_pitch, UINT dst_pitch, UINT update_w, UINT update_h,
6934 const struct wined3d_format *format, DWORD flags, const WINEDDBLTFX *fx)
6935{
6936 UINT row_block_count;
6937 const BYTE *src_row;
6938 BYTE *dst_row;
6939 UINT x, y;
6940
6941 src_row = src_data;
6942 dst_row = dst_data;
6943
6944 row_block_count = (update_w + format->block_width - 1) / format->block_width;
6945
6946 if (!flags)
6947 {
6948 for (y = 0; y < update_h; y += format->block_height)
6949 {
6950 memcpy(dst_row, src_row, row_block_count * format->block_byte_count);
6951 src_row += src_pitch;
6952 dst_row += dst_pitch;
6953 }
6954
6955 return WINED3D_OK;
6956 }
6957
6958 if (flags == WINEDDBLT_DDFX && fx->dwDDFX == WINEDDBLTFX_MIRRORUPDOWN)
6959 {
6960 src_row += (((update_h / format->block_height) - 1) * src_pitch);
6961
6962 switch (format->id)
6963 {
6964 case WINED3DFMT_DXT1:
6965 for (y = 0; y < update_h; y += format->block_height)
6966 {
6967 struct block
6968 {
6969 WORD color[2];
6970 BYTE control_row[4];
6971 };
6972
6973 const struct block *s = (const struct block *)src_row;
6974 struct block *d = (struct block *)dst_row;
6975
6976 for (x = 0; x < row_block_count; ++x)
6977 {
6978 d[x].color[0] = s[x].color[0];
6979 d[x].color[1] = s[x].color[1];
6980 d[x].control_row[0] = s[x].control_row[3];
6981 d[x].control_row[1] = s[x].control_row[2];
6982 d[x].control_row[2] = s[x].control_row[1];
6983 d[x].control_row[3] = s[x].control_row[0];
6984 }
6985 src_row -= src_pitch;
6986 dst_row += dst_pitch;
6987 }
6988 return WINED3D_OK;
6989
6990 case WINED3DFMT_DXT3:
6991 for (y = 0; y < update_h; y += format->block_height)
6992 {
6993 struct block
6994 {
6995 WORD alpha_row[4];
6996 WORD color[2];
6997 BYTE control_row[4];
6998 };
6999
7000 const struct block *s = (const struct block *)src_row;
7001 struct block *d = (struct block *)dst_row;
7002
7003 for (x = 0; x < row_block_count; ++x)
7004 {
7005 d[x].alpha_row[0] = s[x].alpha_row[3];
7006 d[x].alpha_row[1] = s[x].alpha_row[2];
7007 d[x].alpha_row[2] = s[x].alpha_row[1];
7008 d[x].alpha_row[3] = s[x].alpha_row[0];
7009 d[x].color[0] = s[x].color[0];
7010 d[x].color[1] = s[x].color[1];
7011 d[x].control_row[0] = s[x].control_row[3];
7012 d[x].control_row[1] = s[x].control_row[2];
7013 d[x].control_row[2] = s[x].control_row[1];
7014 d[x].control_row[3] = s[x].control_row[0];
7015 }
7016 src_row -= src_pitch;
7017 dst_row += dst_pitch;
7018 }
7019 return WINED3D_OK;
7020
7021 default:
7022 FIXME("Compressed flip not implemented for format %s.\n",
7023 debug_d3dformat(format->id));
7024 return E_NOTIMPL;
7025 }
7026 }
7027
7028 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
7029 debug_d3dformat(format->id), flags, flags & WINEDDBLT_DDFX ? fx->dwDDFX : 0);
7030
7031 return E_NOTIMPL;
7032}
7033
7034static HRESULT surface_cpu_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
7035 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
7036 const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter)
7037{
7038 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
7039 const struct wined3d_format *src_format, *dst_format;
7040 struct wined3d_surface *orig_src = src_surface;
7041 struct wined3d_map_desc dst_map, src_map;
7042 const BYTE *sbase = NULL;
7043 HRESULT hr = WINED3D_OK;
7044 const BYTE *sbuf;
7045 BYTE *dbuf;
7046 int x, y;
7047
7048 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
7049 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
7050 flags, fx, debug_d3dtexturefiltertype(filter));
7051
7052 if (src_surface == dst_surface)
7053 {
7054 wined3d_surface_map(dst_surface, &dst_map, NULL, 0);
7055 src_map = dst_map;
7056 src_format = dst_surface->resource.format;
7057 dst_format = src_format;
7058 }
7059 else
7060 {
7061 dst_format = dst_surface->resource.format;
7062 if (src_surface)
7063 {
7064 if (dst_surface->resource.format->id != src_surface->resource.format->id)
7065 {
7066 src_surface = surface_convert_format(src_surface, dst_format->id);
7067 if (!src_surface)
7068 {
7069 /* The conv function writes a FIXME */
7070 WARN("Cannot convert source surface format to dest format.\n");
7071 goto release;
7072 }
7073 }
7074 wined3d_surface_map(src_surface, &src_map, NULL, WINED3D_MAP_READONLY);
7075 src_format = src_surface->resource.format;
7076 }
7077 else
7078 {
7079 src_format = dst_format;
7080 }
7081
7082 wined3d_surface_map(dst_surface, &dst_map, dst_rect, 0);
7083 }
7084
7085 bpp = dst_surface->resource.format->byte_count;
7086 srcheight = src_rect->bottom - src_rect->top;
7087 srcwidth = src_rect->right - src_rect->left;
7088 dstheight = dst_rect->bottom - dst_rect->top;
7089 dstwidth = dst_rect->right - dst_rect->left;
7090 width = (dst_rect->right - dst_rect->left) * bpp;
7091
7092 if (src_surface)
7093 sbase = (BYTE *)src_map.data
7094 + ((src_rect->top / src_format->block_height) * src_map.row_pitch)
7095 + ((src_rect->left / src_format->block_width) * src_format->block_byte_count);
7096 if (src_surface != dst_surface)
7097 dbuf = dst_map.data;
7098 else
7099 dbuf = (BYTE *)dst_map.data
7100 + ((dst_rect->top / dst_format->block_height) * dst_map.row_pitch)
7101 + ((dst_rect->left / dst_format->block_width) * dst_format->block_byte_count);
7102
7103 if (src_format->flags & dst_format->flags & WINED3DFMT_FLAG_BLOCKS)
7104 {
7105 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
7106
7107 if (src_surface == dst_surface)
7108 {
7109 FIXME("Only plain blits supported on compressed surfaces.\n");
7110 hr = E_NOTIMPL;
7111 goto release;
7112 }
7113
7114 if (srcheight != dstheight || srcwidth != dstwidth)
7115 {
7116 WARN("Stretching not supported on compressed surfaces.\n");
7117 hr = WINED3DERR_INVALIDCALL;
7118 goto release;
7119 }
7120
7121 if (!surface_check_block_align(src_surface, src_rect))
7122 {
7123 WARN("Source rectangle not block-aligned.\n");
7124 hr = WINED3DERR_INVALIDCALL;
7125 goto release;
7126 }
7127
7128 if (!surface_check_block_align(dst_surface, dst_rect))
7129 {
7130 WARN("Destination rectangle not block-aligned.\n");
7131 hr = WINED3DERR_INVALIDCALL;
7132 goto release;
7133 }
7134
7135 hr = surface_cpu_blt_compressed(sbase, dbuf,
7136 src_map.row_pitch, dst_map.row_pitch, dstwidth, dstheight,
7137 src_format, flags, fx);
7138 goto release;
7139 }
7140
7141 /* First, all the 'source-less' blits */
7142 if (flags & WINEDDBLT_COLORFILL)
7143 {
7144 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, fx->u5.dwFillColor);
7145 flags &= ~WINEDDBLT_COLORFILL;
7146 }
7147
7148 if (flags & WINEDDBLT_DEPTHFILL)
7149 {
7150 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
7151 }
7152 if (flags & WINEDDBLT_ROP)
7153 {
7154 /* Catch some degenerate cases here. */
7155 switch (fx->dwROP)
7156 {
7157 case BLACKNESS:
7158 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, 0);
7159 break;
7160 case 0xaa0029: /* No-op */
7161 break;
7162 case WHITENESS:
7163 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, ~0U);
7164 break;
7165 case SRCCOPY: /* Well, we do that below? */
7166 break;
7167 default:
7168 FIXME("Unsupported raster op: %08x Pattern: %p\n", fx->dwROP, fx->u5.lpDDSPattern);
7169 goto error;
7170 }
7171 flags &= ~WINEDDBLT_ROP;
7172 }
7173 if (flags & WINEDDBLT_DDROPS)
7174 {
7175 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", fx->dwDDROP, fx->u5.lpDDSPattern);
7176 }
7177 /* Now the 'with source' blits. */
7178 if (src_surface)
7179 {
7180 int sx, xinc, sy, yinc;
7181
7182 if (!dstwidth || !dstheight) /* Hmm... stupid program? */
7183 goto release;
7184
7185 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT
7186 && (srcwidth != dstwidth || srcheight != dstheight))
7187 {
7188 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
7189 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter));
7190 }
7191
7192 xinc = (srcwidth << 16) / dstwidth;
7193 yinc = (srcheight << 16) / dstheight;
7194
7195 if (!flags)
7196 {
7197 /* No effects, we can cheat here. */
7198 if (dstwidth == srcwidth)
7199 {
7200 if (dstheight == srcheight)
7201 {
7202 /* No stretching in either direction. This needs to be as
7203 * fast as possible. */
7204 sbuf = sbase;
7205
7206 /* Check for overlapping surfaces. */
7207 if (src_surface != dst_surface || dst_rect->top < src_rect->top
7208 || dst_rect->right <= src_rect->left || src_rect->right <= dst_rect->left)
7209 {
7210 /* No overlap, or dst above src, so copy from top downwards. */
7211 for (y = 0; y < dstheight; ++y)
7212 {
7213 memcpy(dbuf, sbuf, width);
7214 sbuf += src_map.row_pitch;
7215 dbuf += dst_map.row_pitch;
7216 }
7217 }
7218 else if (dst_rect->top > src_rect->top)
7219 {
7220 /* Copy from bottom upwards. */
7221 sbuf += src_map.row_pitch * dstheight;
7222 dbuf += dst_map.row_pitch * dstheight;
7223 for (y = 0; y < dstheight; ++y)
7224 {
7225 sbuf -= src_map.row_pitch;
7226 dbuf -= dst_map.row_pitch;
7227 memcpy(dbuf, sbuf, width);
7228 }
7229 }
7230 else
7231 {
7232 /* Src and dst overlapping on the same line, use memmove. */
7233 for (y = 0; y < dstheight; ++y)
7234 {
7235 memmove(dbuf, sbuf, width);
7236 sbuf += src_map.row_pitch;
7237 dbuf += dst_map.row_pitch;
7238 }
7239 }
7240 }
7241 else
7242 {
7243 /* Stretching in y direction only. */
7244 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
7245 {
7246 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
7247 memcpy(dbuf, sbuf, width);
7248 dbuf += dst_map.row_pitch;
7249 }
7250 }
7251 }
7252 else
7253 {
7254 /* Stretching in X direction. */
7255 int last_sy = -1;
7256 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
7257 {
7258 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
7259
7260 if ((sy >> 16) == (last_sy >> 16))
7261 {
7262 /* This source row is the same as last source row -
7263 * Copy the already stretched row. */
7264 memcpy(dbuf, dbuf - dst_map.row_pitch, width);
7265 }
7266 else
7267 {
7268#define STRETCH_ROW(type) \
7269do { \
7270 const type *s = (const type *)sbuf; \
7271 type *d = (type *)dbuf; \
7272 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
7273 d[x] = s[sx >> 16]; \
7274} while(0)
7275
7276 switch(bpp)
7277 {
7278 case 1:
7279 STRETCH_ROW(BYTE);
7280 break;
7281 case 2:
7282 STRETCH_ROW(WORD);
7283 break;
7284 case 4:
7285 STRETCH_ROW(DWORD);
7286 break;
7287 case 3:
7288 {
7289 const BYTE *s;
7290 BYTE *d = dbuf;
7291 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
7292 {
7293 DWORD pixel;
7294
7295 s = sbuf + 3 * (sx >> 16);
7296 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
7297 d[0] = (pixel ) & 0xff;
7298 d[1] = (pixel >> 8) & 0xff;
7299 d[2] = (pixel >> 16) & 0xff;
7300 d += 3;
7301 }
7302 break;
7303 }
7304 default:
7305 FIXME("Stretched blit not implemented for bpp %u!\n", bpp * 8);
7306 hr = WINED3DERR_NOTAVAILABLE;
7307 goto error;
7308 }
7309#undef STRETCH_ROW
7310 }
7311 dbuf += dst_map.row_pitch;
7312 last_sy = sy;
7313 }
7314 }
7315 }
7316 else
7317 {
7318 LONG dstyinc = dst_map.row_pitch, dstxinc = bpp;
7319 DWORD keylow = 0xffffffff, keyhigh = 0, keymask = 0xffffffff;
7320 DWORD destkeylow = 0x0, destkeyhigh = 0xffffffff, destkeymask = 0xffffffff;
7321 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
7322 {
7323 /* The color keying flags are checked for correctness in ddraw */
7324 if (flags & WINEDDBLT_KEYSRC)
7325 {
7326 keylow = src_surface->src_blt_color_key.color_space_low_value;
7327 keyhigh = src_surface->src_blt_color_key.color_space_high_value;
7328 }
7329 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
7330 {
7331 keylow = fx->ddckSrcColorkey.color_space_low_value;
7332 keyhigh = fx->ddckSrcColorkey.color_space_high_value;
7333 }
7334
7335 if (flags & WINEDDBLT_KEYDEST)
7336 {
7337 /* Destination color keys are taken from the source surface! */
7338 destkeylow = src_surface->dst_blt_color_key.color_space_low_value;
7339 destkeyhigh = src_surface->dst_blt_color_key.color_space_high_value;
7340 }
7341 else if (flags & WINEDDBLT_KEYDESTOVERRIDE)
7342 {
7343 destkeylow = fx->ddckDestColorkey.color_space_low_value;
7344 destkeyhigh = fx->ddckDestColorkey.color_space_high_value;
7345 }
7346
7347 if (bpp == 1)
7348 {
7349 keymask = 0xff;
7350 }
7351 else
7352 {
7353 DWORD masks[3];
7354 get_color_masks(src_format, masks);
7355 keymask = masks[0]
7356 | masks[1]
7357 | masks[2];
7358 }
7359 flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
7360 }
7361
7362 if (flags & WINEDDBLT_DDFX)
7363 {
7364 BYTE *dTopLeft, *dTopRight, *dBottomLeft, *dBottomRight, *tmp;
7365 LONG tmpxy;
7366 dTopLeft = dbuf;
7367 dTopRight = dbuf + ((dstwidth - 1) * bpp);
7368 dBottomLeft = dTopLeft + ((dstheight - 1) * dst_map.row_pitch);
7369 dBottomRight = dBottomLeft + ((dstwidth - 1) * bpp);
7370
7371 if (fx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
7372 {
7373 /* I don't think we need to do anything about this flag */
7374 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
7375 }
7376 if (fx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
7377 {
7378 tmp = dTopRight;
7379 dTopRight = dTopLeft;
7380 dTopLeft = tmp;
7381 tmp = dBottomRight;
7382 dBottomRight = dBottomLeft;
7383 dBottomLeft = tmp;
7384 dstxinc = dstxinc * -1;
7385 }
7386 if (fx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
7387 {
7388 tmp = dTopLeft;
7389 dTopLeft = dBottomLeft;
7390 dBottomLeft = tmp;
7391 tmp = dTopRight;
7392 dTopRight = dBottomRight;
7393 dBottomRight = tmp;
7394 dstyinc = dstyinc * -1;
7395 }
7396 if (fx->dwDDFX & WINEDDBLTFX_NOTEARING)
7397 {
7398 /* I don't think we need to do anything about this flag */
7399 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
7400 }
7401 if (fx->dwDDFX & WINEDDBLTFX_ROTATE180)
7402 {
7403 tmp = dBottomRight;
7404 dBottomRight = dTopLeft;
7405 dTopLeft = tmp;
7406 tmp = dBottomLeft;
7407 dBottomLeft = dTopRight;
7408 dTopRight = tmp;
7409 dstxinc = dstxinc * -1;
7410 dstyinc = dstyinc * -1;
7411 }
7412 if (fx->dwDDFX & WINEDDBLTFX_ROTATE270)
7413 {
7414 tmp = dTopLeft;
7415 dTopLeft = dBottomLeft;
7416 dBottomLeft = dBottomRight;
7417 dBottomRight = dTopRight;
7418 dTopRight = tmp;
7419 tmpxy = dstxinc;
7420 dstxinc = dstyinc;
7421 dstyinc = tmpxy;
7422 dstxinc = dstxinc * -1;
7423 }
7424 if (fx->dwDDFX & WINEDDBLTFX_ROTATE90)
7425 {
7426 tmp = dTopLeft;
7427 dTopLeft = dTopRight;
7428 dTopRight = dBottomRight;
7429 dBottomRight = dBottomLeft;
7430 dBottomLeft = tmp;
7431 tmpxy = dstxinc;
7432 dstxinc = dstyinc;
7433 dstyinc = tmpxy;
7434 dstyinc = dstyinc * -1;
7435 }
7436 if (fx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
7437 {
7438 /* I don't think we need to do anything about this flag */
7439 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
7440 }
7441 dbuf = dTopLeft;
7442 flags &= ~(WINEDDBLT_DDFX);
7443 }
7444
7445#define COPY_COLORKEY_FX(type) \
7446do { \
7447 const type *s; \
7448 type *d = (type *)dbuf, *dx, tmp; \
7449 for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
7450 { \
7451 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
7452 dx = d; \
7453 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
7454 { \
7455 tmp = s[sx >> 16]; \
7456 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
7457 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
7458 { \
7459 dx[0] = tmp; \
7460 } \
7461 dx = (type *)(((BYTE *)dx) + dstxinc); \
7462 } \
7463 d = (type *)(((BYTE *)d) + dstyinc); \
7464 } \
7465} while(0)
7466
7467 switch (bpp)
7468 {
7469 case 1:
7470 COPY_COLORKEY_FX(BYTE);
7471 break;
7472 case 2:
7473 COPY_COLORKEY_FX(WORD);
7474 break;
7475 case 4:
7476 COPY_COLORKEY_FX(DWORD);
7477 break;
7478 case 3:
7479 {
7480 const BYTE *s;
7481 BYTE *d = dbuf, *dx;
7482 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
7483 {
7484 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
7485 dx = d;
7486 for (x = sx = 0; x < dstwidth; ++x, sx+= xinc)
7487 {
7488 DWORD pixel, dpixel = 0;
7489 s = sbuf + 3 * (sx>>16);
7490 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
7491 dpixel = dx[0] | (dx[1] << 8 ) | (dx[2] << 16);
7492 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
7493 && ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
7494 {
7495 dx[0] = (pixel ) & 0xff;
7496 dx[1] = (pixel >> 8) & 0xff;
7497 dx[2] = (pixel >> 16) & 0xff;
7498 }
7499 dx += dstxinc;
7500 }
7501 d += dstyinc;
7502 }
7503 break;
7504 }
7505 default:
7506 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
7507 (flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp * 8);
7508 hr = WINED3DERR_NOTAVAILABLE;
7509 goto error;
7510#undef COPY_COLORKEY_FX
7511 }
7512 }
7513 }
7514
7515error:
7516 if (flags && FIXME_ON(d3d_surface))
7517 {
7518 FIXME("\tUnsupported flags: %#x.\n", flags);
7519 }
7520
7521release:
7522 wined3d_surface_unmap(dst_surface);
7523 if (src_surface && src_surface != dst_surface)
7524 wined3d_surface_unmap(src_surface);
7525 /* Release the converted surface, if any. */
7526 if (src_surface && src_surface != orig_src)
7527 wined3d_surface_decref(src_surface);
7528
7529 return hr;
7530}
7531
7532/* Do not call while under the GL lock. */
7533static HRESULT cpu_blit_color_fill(struct wined3d_device *device, struct wined3d_surface *dst_surface,
7534 const RECT *dst_rect, const struct wined3d_color *color)
7535{
7536 static const RECT src_rect;
7537 WINEDDBLTFX BltFx;
7538
7539 memset(&BltFx, 0, sizeof(BltFx));
7540 BltFx.dwSize = sizeof(BltFx);
7541 BltFx.u5.dwFillColor = wined3d_format_convert_from_float(dst_surface, color);
7542 return surface_cpu_blt(dst_surface, dst_rect, NULL, &src_rect,
7543 WINEDDBLT_COLORFILL, &BltFx, WINED3D_TEXF_POINT);
7544}
7545
7546/* Do not call while under the GL lock. */
7547static HRESULT cpu_blit_depth_fill(struct wined3d_device *device,
7548 struct wined3d_surface *surface, const RECT *rect, float depth)
7549{
7550 FIXME("Depth filling not implemented by cpu_blit.\n");
7551 return WINED3DERR_INVALIDCALL;
7552}
7553
7554const struct blit_shader cpu_blit = {
7555 cpu_blit_alloc,
7556 cpu_blit_free,
7557 cpu_blit_set,
7558 cpu_blit_unset,
7559 cpu_blit_supported,
7560 cpu_blit_color_fill,
7561 cpu_blit_depth_fill,
7562};
7563
7564static HRESULT surface_init(struct wined3d_surface *surface, UINT alignment, UINT width, UINT height,
7565 enum wined3d_multisample_type multisample_type, UINT multisample_quality,
7566 struct wined3d_device *device, DWORD usage, enum wined3d_format_id format_id,
7567 enum wined3d_pool pool, DWORD flags, void *parent, const struct wined3d_parent_ops *parent_ops
7568#ifdef VBOX_WITH_WDDM
7569 , HANDLE *shared_handle
7570 , void *pvClientMem
7571#endif
7572 )
7573{
7574 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
7575 const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
7576 BOOL lockable = flags & WINED3D_SURFACE_MAPPABLE;
7577 unsigned int resource_size;
7578 HRESULT hr;
7579
7580 if (multisample_quality > 0)
7581 {
7582 FIXME("multisample_quality set to %u, substituting 0.\n", multisample_quality);
7583 multisample_quality = 0;
7584 }
7585
7586 /* Quick lockable sanity check.
7587 * TODO: remove this after surfaces, usage and lockability have been debugged properly
7588 * this function is too deep to need to care about things like this.
7589 * Levels need to be checked too, since they all affect what can be done. */
7590 switch (pool)
7591 {
7592 case WINED3D_POOL_SCRATCH:
7593 if (!lockable)
7594 {
7595 FIXME("Called with a pool of SCRATCH and a lockable of FALSE "
7596 "which are mutually exclusive, setting lockable to TRUE.\n");
7597 lockable = TRUE;
7598 }
7599 break;
7600
7601 case WINED3D_POOL_SYSTEM_MEM:
7602 if (!lockable)
7603 FIXME("Called with a pool of SYSTEMMEM and a lockable of FALSE, this is acceptable but unexpected.\n");
7604 break;
7605
7606 case WINED3D_POOL_MANAGED:
7607 if (usage & WINED3DUSAGE_DYNAMIC)
7608 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
7609 break;
7610
7611 case WINED3D_POOL_DEFAULT:
7612 if (lockable && !(usage & (WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
7613 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
7614 break;
7615
7616 default:
7617 FIXME("Unknown pool %#x.\n", pool);
7618 break;
7619 };
7620
7621 if (usage & WINED3DUSAGE_RENDERTARGET && pool != WINED3D_POOL_DEFAULT)
7622 FIXME("Trying to create a render target that isn't in the default pool.\n");
7623
7624 /* FIXME: Check that the format is supported by the device. */
7625
7626 resource_size = wined3d_format_calculate_size(format, alignment, width, height);
7627 if (!resource_size)
7628 return WINED3DERR_INVALIDCALL;
7629
7630 if (device->wined3d->flags & WINED3D_NO3D)
7631 surface->surface_ops = &gdi_surface_ops;
7632 else
7633 surface->surface_ops = &surface_ops;
7634
7635 hr = resource_init(&surface->resource, device, WINED3D_RTYPE_SURFACE, format,
7636 multisample_type, multisample_quality, usage, pool, width, height, 1,
7637 resource_size, parent, parent_ops, &surface_resource_ops
7638#ifdef VBOX_WITH_WDDM
7639 , shared_handle
7640 , pvClientMem
7641#endif
7642 );
7643 if (FAILED(hr))
7644 {
7645 WARN("Failed to initialize resource, returning %#x.\n", hr);
7646 return hr;
7647 }
7648
7649#ifdef VBOX_WITH_WDDM
7650 /* this will be a nop for the non-shared resource,
7651 * for the shared resource this will ensure the surface is initialized properly */
7652 surface_shrc_lock(surface);
7653#endif
7654
7655 /* "Standalone" surface. */
7656 surface_set_container(surface, NULL);
7657
7658 list_init(&surface->overlays);
7659
7660 /* Flags */
7661 surface->flags = SFLAG_NORMCOORD; /* Default to normalized coords. */
7662 if (flags & WINED3D_SURFACE_DISCARD)
7663 surface->flags |= SFLAG_DISCARD;
7664 if (flags & WINED3D_SURFACE_PIN_SYSMEM)
7665 surface->flags |= SFLAG_PIN_SYSMEM;
7666 if (lockable || format_id == WINED3DFMT_D16_LOCKABLE)
7667 surface->flags |= SFLAG_LOCKABLE;
7668 /* I'm not sure if this qualifies as a hack or as an optimization. It
7669 * seems reasonable to assume that lockable render targets will get
7670 * locked, so we might as well set SFLAG_DYNLOCK right at surface
7671 * creation. However, the other reason we want to do this is that several
7672 * ddraw applications access surface memory while the surface isn't
7673 * mapped. The SFLAG_DYNLOCK behaviour of keeping SYSMEM around for
7674 * future locks prevents these from crashing. */
7675 if (lockable && (usage & WINED3DUSAGE_RENDERTARGET))
7676 surface->flags |= SFLAG_DYNLOCK;
7677#ifdef VBOX_WITH_WDDM
7678 if (pool == WINED3D_POOL_SYSTEM_MEM && pvClientMem) surface->flags |= SFLAG_CLIENTMEM;
7679#endif
7680
7681 /* Mark the texture as dirty so that it gets loaded first time around. */
7682 surface_add_dirty_rect(surface, NULL);
7683 list_init(&surface->renderbuffers);
7684
7685 TRACE("surface %p, memory %p, size %u\n",
7686 surface, surface->resource.allocatedMemory, surface->resource.size);
7687
7688 /* Call the private setup routine */
7689 hr = surface->surface_ops->surface_private_setup(surface);
7690 if (FAILED(hr))
7691 {
7692 ERR("Private setup failed, returning %#x\n", hr);
7693 surface_cleanup(surface);
7694 return hr;
7695 }
7696
7697 /* Similar to lockable rendertargets above, creating the DIB section
7698 * during surface initialization prevents the sysmem pointer from changing
7699 * after a wined3d_surface_getdc() call. */
7700 if ((usage & WINED3DUSAGE_OWNDC) && !surface->hDC
7701 && SUCCEEDED(surface_create_dib_section(surface)))
7702 {
7703 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7704 surface->resource.heapMemory = NULL;
7705 surface->resource.allocatedMemory = surface->dib.bitmap_data;
7706 }
7707
7708#ifdef VBOX_WITH_WDDM
7709 if (VBOXSHRC_IS_SHARED(surface))
7710 {
7711 Assert(shared_handle);
7712 if (!VBOXSHRC_IS_SHARED_OPENED(surface))
7713 {
7714 surface_shrc_unlock(surface);
7715 Assert(!(*shared_handle));
7716 *shared_handle = VBOXSHRC_GET_SHAREHANDLE(surface);
7717 }
7718 else
7719 {
7720 VBOXSHRC_UNLOCK(surface);
7721 Assert(!VBOXSHRC_IS_LOCKED(surface));
7722#ifdef DEBUG_misha
7723 ERR("test this!");
7724#endif
7725 surface_setup_location_onopen(surface);
7726 Assert(*shared_handle);
7727 Assert(*shared_handle == VBOXSHRC_GET_SHAREHANDLE(surface));
7728 }
7729
7730 Assert(!device->isInDraw);
7731
7732 /* flush to ensure the texture is allocated/referenced before it is used/released by another
7733 * process opening/creating it */
7734 /* flush to ensure the texture is allocated/referenced before it is used/released by another
7735 * process opening/creating it */
7736 Assert(device->context_count == 1);
7737 pVBoxFlushToHost(device->contexts[0]->glCtx);
7738 }
7739 else
7740 {
7741 Assert(!shared_handle);
7742 }
7743#endif
7744
7745 return hr;
7746}
7747
7748HRESULT CDECL wined3d_surface_create(struct wined3d_device *device, UINT width, UINT height,
7749 enum wined3d_format_id format_id, DWORD usage, enum wined3d_pool pool,
7750 enum wined3d_multisample_type multisample_type, DWORD multisample_quality, DWORD flags,
7751 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_surface **surface
7752#ifdef VBOX_WITH_WDDM
7753 , HANDLE *shared_handle
7754 , void *pvClientMem
7755#endif
7756 )
7757{
7758 struct wined3d_surface *object;
7759 HRESULT hr;
7760
7761 TRACE("device %p, width %u, height %u, format %s\n",
7762 device, width, height, debug_d3dformat(format_id));
7763 TRACE("surface %p, usage %s (%#x), pool %s, multisample_type %#x, multisample_quality %u\n",
7764 surface, debug_d3dusage(usage), usage, debug_d3dpool(pool), multisample_type, multisample_quality);
7765 TRACE("flags %#x, parent %p, parent_ops %p.\n", flags, parent, parent_ops);
7766
7767 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
7768 if (!object)
7769 return WINED3DERR_OUTOFVIDEOMEMORY;
7770
7771#ifdef VBOX_WITH_WDDM
7772 if (FAILED(hr = surface_init(object, device->surface_alignment, width, height, multisample_type,
7773 multisample_quality, device, usage, format_id, pool, flags, parent, parent_ops
7774 , shared_handle
7775 , pvClientMem
7776 )))
7777#else
7778 if (FAILED(hr = surface_init(object, device->surface_alignment, width, height, multisample_type,
7779 multisample_quality, device, usage, format_id, pool, flags, parent, parent_ops)))
7780#endif
7781 {
7782 WARN("Failed to initialize surface, returning %#x.\n", hr);
7783 HeapFree(GetProcessHeap(), 0, object);
7784 return hr;
7785 }
7786
7787 TRACE("Created surface %p.\n", object);
7788 *surface = object;
7789
7790 return hr;
7791}
7792
7793#ifdef VBOX_WITH_WDDM
7794HRESULT CDECL wined3d_surface_get_host_id(struct wined3d_surface *surface, uint32_t *id)
7795{
7796 struct wined3d_texture *texture;
7797 surface_internal_preload(surface, SRGB_RGB);
7798
7799 texture = surface->container;
7800 if (texture && texture->level_count != 1 && texture->layer_count != 1)
7801 {
7802 ERR("unsupported level(%d) or layer(%d) count", texture->level_count, texture->layer_count);
7803 }
7804
7805 if (!surface->texture_name)
7806 {
7807 ERR("no texture name!");
7808 return E_FAIL;
7809 }
7810
7811 *id = surface->texture_name;
7812 return S_OK;
7813}
7814
7815HRESULT CDECL wined3d_surface_sync_to_host(struct wined3d_surface *surface)
7816{
7817 HRESULT hr = surface_load_location(surface, SFLAG_INTEXTURE, NULL);
7818 if (!SUCCEEDED(hr))
7819 {
7820 ERR("surface_load_location failed hr 0x%x", hr);
7821 return hr;
7822 }
7823
7824 return S_OK;
7825}
7826#endif
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