VirtualBox

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

Last change on this file since 69362 was 63025, checked in by vboxsync, 9 years ago

GA/NT/Graphics: warnings

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 278.0 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#ifdef VBOX_WITH_WINE_FIX_SURFUPDATA
2636 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
2637#endif
2638 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, src_pitch / format->byte_count);
2639 gl_info->gl_ops.gl.p_glTexSubImage2D(surface->texture_target, surface->texture_level,
2640 dst_point->x, dst_point->y, update_w, update_h, format->glFormat, format->glType, addr);
2641 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
2642#ifdef VBOX_WITH_WINE_FIX_SURFUPDATA
2643 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ALIGNMENT, surface->resource.device->surface_alignment);
2644#endif
2645 checkGLcall("glTexSubImage2D");
2646 }
2647
2648 if (data->buffer_object)
2649 {
2650 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
2651 checkGLcall("glBindBufferARB");
2652 }
2653
2654 if (wined3d_settings.strict_draw_ordering)
2655 gl_info->gl_ops.gl.p_glFlush();
2656
2657 if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
2658 {
2659 struct wined3d_device *device = surface->resource.device;
2660 unsigned int i;
2661
2662 for (i = 0; i < device->context_count; ++i)
2663 {
2664 context_surface_update(device->contexts[i], surface);
2665 }
2666 }
2667}
2668
2669static HRESULT d3dfmt_get_conv(const struct wined3d_surface *surface, BOOL need_alpha_ck, BOOL use_texturing,
2670 struct wined3d_format *format, enum wined3d_conversion_type *conversion_type)
2671{
2672 BOOL colorkey_active = need_alpha_ck && (surface->CKeyFlags & WINEDDSD_CKSRCBLT);
2673 const struct wined3d_device *device = surface->resource.device;
2674 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
2675 BOOL blit_supported = FALSE;
2676
2677 /* Copy the default values from the surface. Below we might perform fixups */
2678 /* TODO: get rid of color keying desc fixups by using e.g. a table. */
2679 *format = *surface->resource.format;
2680 *conversion_type = WINED3D_CT_NONE;
2681
2682 /* Ok, now look if we have to do any conversion */
2683 switch (surface->resource.format->id)
2684 {
2685 case WINED3DFMT_P8_UINT:
2686 /* Below the call to blit_supported is disabled for Wine 1.2
2687 * because the function isn't operating correctly yet. At the
2688 * moment 8-bit blits are handled in software and if certain GL
2689 * extensions are around, surface conversion is performed at
2690 * upload time. The blit_supported call recognizes it as a
2691 * destination fixup. This type of upload 'fixup' and 8-bit to
2692 * 8-bit blits need to be handled by the blit_shader.
2693 * TODO: get rid of this #if 0. */
2694#if 0
2695 blit_supported = device->blitter->blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
2696 &rect, surface->resource.usage, surface->resource.pool, surface->resource.format,
2697 &rect, surface->resource.usage, surface->resource.pool, surface->resource.format);
2698#endif
2699 blit_supported = gl_info->supported[EXT_PALETTED_TEXTURE] || gl_info->supported[ARB_FRAGMENT_PROGRAM];
2700
2701 /* Use conversion when the blit_shader backend supports it. It only supports this in case of
2702 * texturing. Further also use conversion in case of color keying.
2703 * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
2704 * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
2705 * conflicts with this.
2706 */
2707 if (!((blit_supported && device->fb.render_targets && surface == device->fb.render_targets[0]))
2708 || colorkey_active || !use_texturing)
2709 {
2710 format->glFormat = GL_RGBA;
2711 format->glInternal = GL_RGBA;
2712 format->glType = GL_UNSIGNED_BYTE;
2713 format->conv_byte_count = 4;
2714 if (colorkey_active)
2715 *conversion_type = WINED3D_CT_PALETTED_CK;
2716 else
2717 *conversion_type = WINED3D_CT_PALETTED;
2718 }
2719 break;
2720
2721 case WINED3DFMT_B2G3R3_UNORM:
2722 /* **********************
2723 GL_UNSIGNED_BYTE_3_3_2
2724 ********************** */
2725 if (colorkey_active) {
2726 /* This texture format will never be used.. So do not care about color keying
2727 up until the point in time it will be needed :-) */
2728 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
2729 }
2730 break;
2731
2732 case WINED3DFMT_B5G6R5_UNORM:
2733 if (colorkey_active)
2734 {
2735 *conversion_type = WINED3D_CT_CK_565;
2736 format->glFormat = GL_RGBA;
2737 format->glInternal = GL_RGB5_A1;
2738 format->glType = GL_UNSIGNED_SHORT_5_5_5_1;
2739 format->conv_byte_count = 2;
2740 }
2741 break;
2742
2743 case WINED3DFMT_B5G5R5X1_UNORM:
2744 if (colorkey_active)
2745 {
2746 *conversion_type = WINED3D_CT_CK_5551;
2747 format->glFormat = GL_BGRA;
2748 format->glInternal = GL_RGB5_A1;
2749 format->glType = GL_UNSIGNED_SHORT_1_5_5_5_REV;
2750 format->conv_byte_count = 2;
2751 }
2752 break;
2753
2754 case WINED3DFMT_B8G8R8_UNORM:
2755 if (colorkey_active)
2756 {
2757 *conversion_type = WINED3D_CT_CK_RGB24;
2758 format->glFormat = GL_RGBA;
2759 format->glInternal = GL_RGBA8;
2760 format->glType = GL_UNSIGNED_INT_8_8_8_8;
2761 format->conv_byte_count = 4;
2762 }
2763 break;
2764
2765 case WINED3DFMT_B8G8R8X8_UNORM:
2766 if (colorkey_active)
2767 {
2768 *conversion_type = WINED3D_CT_RGB32_888;
2769 format->glFormat = GL_RGBA;
2770 format->glInternal = GL_RGBA8;
2771 format->glType = GL_UNSIGNED_INT_8_8_8_8;
2772 format->conv_byte_count = 4;
2773 }
2774 break;
2775
2776 case WINED3DFMT_B8G8R8A8_UNORM:
2777 if (colorkey_active)
2778 {
2779 *conversion_type = WINED3D_CT_CK_ARGB32;
2780 format->conv_byte_count = 4;
2781 }
2782 break;
2783
2784 default:
2785 break;
2786 }
2787
2788 if (*conversion_type != WINED3D_CT_NONE)
2789 {
2790 format->rtInternal = format->glInternal;
2791 format->glGammaInternal = format->glInternal;
2792 }
2793
2794 return WINED3D_OK;
2795}
2796
2797static BOOL surface_check_block_align(struct wined3d_surface *surface, const RECT *rect)
2798{
2799 UINT width_mask, height_mask;
2800
2801 if (!rect->left && !rect->top
2802 && rect->right == surface->resource.width
2803 && rect->bottom == surface->resource.height)
2804 return TRUE;
2805
2806 /* This assumes power of two block sizes, but NPOT block sizes would be
2807 * silly anyway. */
2808 width_mask = surface->resource.format->block_width - 1;
2809 height_mask = surface->resource.format->block_height - 1;
2810
2811 if (!(rect->left & width_mask) && !(rect->top & height_mask)
2812 && !(rect->right & width_mask) && !(rect->bottom & height_mask))
2813 return TRUE;
2814
2815 return FALSE;
2816}
2817
2818HRESULT surface_upload_from_surface(struct wined3d_surface *dst_surface, const POINT *dst_point,
2819 struct wined3d_surface *src_surface, const RECT *src_rect)
2820{
2821 const struct wined3d_format *src_format;
2822 const struct wined3d_format *dst_format;
2823 const struct wined3d_gl_info *gl_info;
2824 enum wined3d_conversion_type convert;
2825 struct wined3d_context *context;
2826 struct wined3d_bo_address data;
2827 struct wined3d_format format;
2828 UINT update_w, update_h;
2829 UINT dst_w, dst_h;
2830 RECT r, dst_rect;
2831 UINT src_pitch;
2832 POINT p;
2833
2834 TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
2835 dst_surface, wine_dbgstr_point(dst_point),
2836 src_surface, wine_dbgstr_rect(src_rect));
2837
2838 src_format = src_surface->resource.format;
2839 dst_format = dst_surface->resource.format;
2840
2841 if (src_format->id != dst_format->id)
2842 {
2843 WARN("Source and destination surfaces should have the same format.\n");
2844 return WINED3DERR_INVALIDCALL;
2845 }
2846
2847 if (!dst_point)
2848 {
2849 p.x = 0;
2850 p.y = 0;
2851 dst_point = &p;
2852 }
2853 else if (dst_point->x < 0 || dst_point->y < 0)
2854 {
2855 WARN("Invalid destination point.\n");
2856 return WINED3DERR_INVALIDCALL;
2857 }
2858
2859 if (!src_rect)
2860 {
2861 r.left = 0;
2862 r.top = 0;
2863 r.right = src_surface->resource.width;
2864 r.bottom = src_surface->resource.height;
2865 src_rect = &r;
2866 }
2867 else if (src_rect->left < 0 || src_rect->left >= src_rect->right
2868 || src_rect->top < 0 || src_rect->top >= src_rect->bottom)
2869 {
2870 WARN("Invalid source rectangle.\n");
2871 return WINED3DERR_INVALIDCALL;
2872 }
2873
2874 dst_w = dst_surface->resource.width;
2875 dst_h = dst_surface->resource.height;
2876
2877 update_w = src_rect->right - src_rect->left;
2878 update_h = src_rect->bottom - src_rect->top;
2879
2880 if (update_w > dst_w || dst_point->x > dst_w - update_w
2881 || update_h > dst_h || dst_point->y > dst_h - update_h)
2882 {
2883 WARN("Destination out of bounds.\n");
2884 return WINED3DERR_INVALIDCALL;
2885 }
2886
2887 if ((src_format->flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align(src_surface, src_rect))
2888 {
2889 WARN("Source rectangle not block-aligned.\n");
2890 return WINED3DERR_INVALIDCALL;
2891 }
2892
2893 SetRect(&dst_rect, dst_point->x, dst_point->y, dst_point->x + update_w, dst_point->y + update_h);
2894 if ((dst_format->flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align(dst_surface, &dst_rect))
2895 {
2896 WARN("Destination rectangle not block-aligned.\n");
2897 return WINED3DERR_INVALIDCALL;
2898 }
2899
2900 /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
2901 d3dfmt_get_conv(dst_surface, FALSE, TRUE, &format, &convert);
2902 if (convert != WINED3D_CT_NONE || format.convert)
2903 return wined3d_surface_blt(dst_surface, &dst_rect, src_surface, src_rect, 0, NULL, WINED3D_TEXF_POINT);
2904
2905 context = context_acquire(dst_surface->resource.device, NULL);
2906 gl_info = context->gl_info;
2907
2908 /* Only load the surface for partial updates. For newly allocated texture
2909 * the texture wouldn't be the current location, and we'd upload zeroes
2910 * just to overwrite them again. */
2911 if (update_w == dst_w && update_h == dst_h)
2912 surface_prepare_texture(dst_surface, context, FALSE);
2913 else
2914 surface_load_location(dst_surface, SFLAG_INTEXTURE, NULL);
2915 surface_bind(dst_surface, context, FALSE);
2916
2917 data.buffer_object = src_surface->pbo;
2918 data.addr = src_surface->resource.allocatedMemory;
2919 src_pitch = wined3d_surface_get_pitch(src_surface);
2920
2921 surface_upload_data(dst_surface, gl_info, src_format, src_rect, src_pitch, dst_point, FALSE, &data);
2922
2923 invalidate_active_texture(dst_surface->resource.device, context);
2924
2925 context_release(context);
2926
2927 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
2928 return WINED3D_OK;
2929}
2930
2931/* This call just allocates the texture, the caller is responsible for binding
2932 * the correct texture. */
2933/* Context activation is done by the caller. */
2934static void surface_allocate_surface(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
2935 const struct wined3d_format *format, BOOL srgb)
2936{
2937 BOOL enable_client_storage = FALSE;
2938 GLsizei width = surface->pow2Width;
2939 GLsizei height = surface->pow2Height;
2940 const BYTE *mem = NULL;
2941 GLenum internal;
2942
2943#ifdef VBOX_WITH_WDDM
2944 if (VBOXSHRC_IS_SHARED_OPENED(surface))
2945 {
2946 ERR("trying to allocate shared openned resource!!, ignoring..\n");
2947 return;
2948 }
2949#endif
2950
2951 if (srgb)
2952 {
2953 internal = format->glGammaInternal;
2954 }
2955 else if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(surface))
2956 {
2957 internal = format->rtInternal;
2958 }
2959 else
2960 {
2961 internal = format->glInternal;
2962 }
2963
2964 if (!internal)
2965 FIXME("No GL internal format for format %s.\n", debug_d3dformat(format->id));
2966
2967 if (format->flags & WINED3DFMT_FLAG_HEIGHT_SCALE)
2968 {
2969 height *= format->height_scale.numerator;
2970 height /= format->height_scale.denominator;
2971 }
2972
2973 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",
2974 surface, surface->texture_target, surface->texture_level, debug_d3dformat(format->id),
2975 internal, width, height, format->glFormat, format->glType);
2976
2977 if (gl_info->supported[APPLE_CLIENT_STORAGE])
2978 {
2979 if (surface->flags & (SFLAG_NONPOW2 | SFLAG_DIBSECTION | SFLAG_CONVERTED)
2980 || !surface->resource.allocatedMemory)
2981 {
2982 /* In some cases we want to disable client storage.
2983 * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
2984 * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
2985 * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
2986 * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively
2987 */
2988 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2989 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2990 surface->flags &= ~SFLAG_CLIENT;
2991 enable_client_storage = TRUE;
2992 }
2993 else
2994 {
2995 surface->flags |= SFLAG_CLIENT;
2996
2997 /* Point OpenGL to our allocated texture memory. Do not use
2998 * resource.allocatedMemory here because it might point into a
2999 * PBO. Instead use heapMemory, but get the alignment right. */
3000 mem = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory
3001 + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
3002 }
3003 }
3004
3005 if (format->flags & WINED3DFMT_FLAG_COMPRESSED && mem)
3006 {
3007 GL_EXTCALL(glCompressedTexImage2DARB(surface->texture_target, surface->texture_level,
3008 internal, width, height, 0, surface->resource.size, mem));
3009 checkGLcall("glCompressedTexImage2DARB");
3010 }
3011 else
3012 {
3013 gl_info->gl_ops.gl.p_glTexImage2D(surface->texture_target, surface->texture_level,
3014 internal, width, height, 0, format->glFormat, format->glType, mem);
3015 checkGLcall("glTexImage2D");
3016 }
3017
3018 if (enable_client_storage)
3019 {
3020 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
3021 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
3022 }
3023}
3024
3025/* In D3D the depth stencil dimensions have to be greater than or equal to the
3026 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
3027/* TODO: We should synchronize the renderbuffer's content with the texture's content. */
3028/* Context activation is done by the caller. */
3029void surface_set_compatible_renderbuffer(struct wined3d_surface *surface, const struct wined3d_surface *rt)
3030{
3031 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
3032 struct wined3d_renderbuffer_entry *entry;
3033 GLuint renderbuffer = 0;
3034 unsigned int src_width, src_height;
3035 unsigned int width, height;
3036
3037 if (rt && rt->resource.format->id != WINED3DFMT_NULL)
3038 {
3039 width = rt->pow2Width;
3040 height = rt->pow2Height;
3041 }
3042 else
3043 {
3044 width = surface->pow2Width;
3045 height = surface->pow2Height;
3046 }
3047
3048 src_width = surface->pow2Width;
3049 src_height = surface->pow2Height;
3050
3051 /* A depth stencil smaller than the render target is not valid */
3052 if (width > src_width || height > src_height) return;
3053
3054 /* Remove any renderbuffer set if the sizes match */
3055 if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]
3056 || (width == src_width && height == src_height))
3057 {
3058 surface->current_renderbuffer = NULL;
3059 return;
3060 }
3061
3062 /* Look if we've already got a renderbuffer of the correct dimensions */
3063 LIST_FOR_EACH_ENTRY(entry, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
3064 {
3065 if (entry->width == width && entry->height == height)
3066 {
3067 renderbuffer = entry->id;
3068 surface->current_renderbuffer = entry;
3069 break;
3070 }
3071 }
3072
3073 if (!renderbuffer)
3074 {
3075 gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
3076 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
3077 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER,
3078 surface->resource.format->glInternal, width, height);
3079
3080 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
3081 entry->width = width;
3082 entry->height = height;
3083 entry->id = renderbuffer;
3084 list_add_head(&surface->renderbuffers, &entry->entry);
3085
3086 surface->current_renderbuffer = entry;
3087 }
3088
3089 checkGLcall("set_compatible_renderbuffer");
3090}
3091
3092GLenum surface_get_gl_buffer(const struct wined3d_surface *surface)
3093{
3094 const struct wined3d_swapchain *swapchain = surface->swapchain;
3095
3096 TRACE("surface %p.\n", surface);
3097
3098 if (!swapchain)
3099 {
3100 ERR("Surface %p is not on a swapchain.\n", surface);
3101 return GL_NONE;
3102 }
3103
3104 if (swapchain->back_buffers && swapchain->back_buffers[0] == surface)
3105 {
3106 if (swapchain->render_to_fbo)
3107 {
3108 TRACE("Returning GL_COLOR_ATTACHMENT0\n");
3109 return GL_COLOR_ATTACHMENT0;
3110 }
3111 TRACE("Returning GL_BACK\n");
3112 return GL_BACK;
3113 }
3114 else if (surface == swapchain->front_buffer)
3115 {
3116 TRACE("Returning GL_FRONT\n");
3117 return GL_FRONT;
3118 }
3119
3120 FIXME("Higher back buffer, returning GL_BACK\n");
3121 return GL_BACK;
3122}
3123
3124/* Slightly inefficient way to handle multiple dirty rects but it works :) */
3125void surface_add_dirty_rect(struct wined3d_surface *surface, const struct wined3d_box *dirty_rect)
3126{
3127 TRACE("surface %p, dirty_rect %p.\n", surface, dirty_rect);
3128
3129 if (!(surface->flags & SFLAG_INSYSMEM) && (surface->flags & SFLAG_INTEXTURE))
3130 /* No partial locking for textures yet. */
3131 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
3132
3133 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
3134 if (dirty_rect)
3135 {
3136 surface->dirtyRect.left = min(surface->dirtyRect.left, dirty_rect->left);
3137 surface->dirtyRect.top = min(surface->dirtyRect.top, dirty_rect->top);
3138 surface->dirtyRect.right = max(surface->dirtyRect.right, dirty_rect->right);
3139 surface->dirtyRect.bottom = max(surface->dirtyRect.bottom, dirty_rect->bottom);
3140 }
3141 else
3142 {
3143 surface->dirtyRect.left = 0;
3144 surface->dirtyRect.top = 0;
3145 surface->dirtyRect.right = surface->resource.width;
3146 surface->dirtyRect.bottom = surface->resource.height;
3147 }
3148
3149 /* if the container is a texture then mark it dirty. */
3150 if (surface->container)
3151 {
3152 TRACE("Passing to container.\n");
3153 wined3d_texture_set_dirty(surface->container, TRUE);
3154 }
3155}
3156
3157HRESULT surface_load(struct wined3d_surface *surface, BOOL srgb)
3158{
3159 DWORD flag = srgb ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
3160 BOOL ck_changed;
3161
3162 TRACE("surface %p, srgb %#x.\n", surface, srgb);
3163
3164 if (surface->resource.pool == WINED3D_POOL_SCRATCH)
3165 {
3166 ERR("Not supported on scratch surfaces.\n");
3167 return WINED3DERR_INVALIDCALL;
3168 }
3169
3170 ck_changed = !(surface->flags & SFLAG_GLCKEY) != !(surface->CKeyFlags & WINEDDSD_CKSRCBLT);
3171
3172 /* Reload if either the texture and sysmem have different ideas about the
3173 * color key, or the actual key values changed. */
3174 if (ck_changed || ((surface->CKeyFlags & WINEDDSD_CKSRCBLT)
3175 && (surface->gl_color_key.color_space_low_value != surface->src_blt_color_key.color_space_low_value
3176 || surface->gl_color_key.color_space_high_value != surface->src_blt_color_key.color_space_high_value)))
3177 {
3178 TRACE("Reloading because of color keying\n");
3179 /* To perform the color key conversion we need a sysmem copy of
3180 * the surface. Make sure we have it. */
3181
3182 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
3183 /* Make sure the texture is reloaded because of the color key change,
3184 * this kills performance though :( */
3185 /* TODO: This is not necessarily needed with hw palettized texture support. */
3186 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
3187 /* Switching color keying on / off may change the internal format. */
3188 if (ck_changed)
3189 surface_force_reload(surface);
3190 }
3191 else if (!(surface->flags & flag))
3192 {
3193 TRACE("Reloading because surface is dirty.\n");
3194 }
3195 else
3196 {
3197 TRACE("surface is already in texture\n");
3198 return WINED3D_OK;
3199 }
3200
3201 /* No partial locking for textures yet. */
3202 surface_load_location(surface, flag, NULL);
3203 surface_evict_sysmem(surface);
3204
3205 return WINED3D_OK;
3206}
3207
3208/* See also float_16_to_32() in wined3d_private.h */
3209static inline unsigned short float_32_to_16(const float *in)
3210{
3211 int exp = 0;
3212 float tmp = fabsf(*in);
3213 unsigned int mantissa;
3214 unsigned short ret;
3215
3216 /* Deal with special numbers */
3217 if (*in == 0.0f)
3218 return 0x0000;
3219 if (isnan(*in))
3220 return 0x7c01;
3221 if (isinf(*in))
3222 return (*in < 0.0f ? 0xfc00 : 0x7c00);
3223
3224 if (tmp < powf(2, 10))
3225 {
3226 do
3227 {
3228 tmp = tmp * 2.0f;
3229 exp--;
3230 } while (tmp < powf(2, 10));
3231 }
3232 else if (tmp >= powf(2, 11))
3233 {
3234 do
3235 {
3236 tmp /= 2.0f;
3237 exp++;
3238 } while (tmp >= powf(2, 11));
3239 }
3240
3241 mantissa = (unsigned int)tmp;
3242 if (tmp - mantissa >= 0.5f)
3243 ++mantissa; /* Round to nearest, away from zero. */
3244
3245 exp += 10; /* Normalize the mantissa. */
3246 exp += 15; /* Exponent is encoded with excess 15. */
3247
3248 if (exp > 30) /* too big */
3249 {
3250 ret = 0x7c00; /* INF */
3251 }
3252 else if (exp <= 0)
3253 {
3254 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
3255 while (exp <= 0)
3256 {
3257 mantissa = mantissa >> 1;
3258 ++exp;
3259 }
3260 ret = mantissa & 0x3ff;
3261 }
3262 else
3263 {
3264 ret = (exp << 10) | (mantissa & 0x3ff);
3265 }
3266
3267 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
3268 return ret;
3269}
3270
3271ULONG CDECL wined3d_surface_incref(struct wined3d_surface *surface)
3272{
3273 ULONG refcount;
3274
3275 TRACE("surface %p, swapchain %p, container %p.\n",
3276 surface, surface->swapchain, surface->container);
3277
3278 if (surface->swapchain)
3279 return wined3d_swapchain_incref(surface->swapchain);
3280
3281 if (surface->container)
3282 return wined3d_texture_incref(surface->container);
3283
3284 refcount = InterlockedIncrement(&surface->resource.ref);
3285 TRACE("%p increasing refcount to %u.\n", surface, refcount);
3286
3287 return refcount;
3288}
3289
3290/* Do not call while under the GL lock. */
3291ULONG CDECL wined3d_surface_decref(struct wined3d_surface *surface)
3292{
3293 ULONG refcount;
3294
3295 TRACE("surface %p, swapchain %p, container %p.\n",
3296 surface, surface->swapchain, surface->container);
3297
3298 if (surface->swapchain)
3299 return wined3d_swapchain_decref(surface->swapchain);
3300
3301 if (surface->container)
3302 return wined3d_texture_decref(surface->container);
3303
3304 refcount = InterlockedDecrement(&surface->resource.ref);
3305 TRACE("%p decreasing refcount to %u.\n", surface, refcount);
3306
3307 if (!refcount)
3308 {
3309 surface_cleanup(surface);
3310 surface->resource.parent_ops->wined3d_object_destroyed(surface->resource.parent);
3311
3312 TRACE("Destroyed surface %p.\n", surface);
3313 HeapFree(GetProcessHeap(), 0, surface);
3314 }
3315
3316 return refcount;
3317}
3318
3319DWORD CDECL wined3d_surface_set_priority(struct wined3d_surface *surface, DWORD priority)
3320{
3321 return resource_set_priority(&surface->resource, priority);
3322}
3323
3324DWORD CDECL wined3d_surface_get_priority(const struct wined3d_surface *surface)
3325{
3326 return resource_get_priority(&surface->resource);
3327}
3328
3329void CDECL wined3d_surface_preload(struct wined3d_surface *surface)
3330{
3331 TRACE("surface %p.\n", surface);
3332
3333 if (!surface->resource.device->d3d_initialized)
3334 {
3335 ERR("D3D not initialized.\n");
3336 return;
3337 }
3338
3339 surface_internal_preload(surface, SRGB_ANY);
3340}
3341
3342void * CDECL wined3d_surface_get_parent(const struct wined3d_surface *surface)
3343{
3344 TRACE("surface %p.\n", surface);
3345
3346 return surface->resource.parent;
3347}
3348
3349struct wined3d_resource * CDECL wined3d_surface_get_resource(struct wined3d_surface *surface)
3350{
3351 TRACE("surface %p.\n", surface);
3352
3353 return &surface->resource;
3354}
3355
3356HRESULT CDECL wined3d_surface_get_blt_status(const struct wined3d_surface *surface, DWORD flags)
3357{
3358 TRACE("surface %p, flags %#x.\n", surface, flags);
3359
3360 switch (flags)
3361 {
3362 case WINEDDGBS_CANBLT:
3363 case WINEDDGBS_ISBLTDONE:
3364 return WINED3D_OK;
3365
3366 default:
3367 return WINED3DERR_INVALIDCALL;
3368 }
3369}
3370
3371HRESULT CDECL wined3d_surface_get_flip_status(const struct wined3d_surface *surface, DWORD flags)
3372{
3373 TRACE("surface %p, flags %#x.\n", surface, flags);
3374
3375 /* XXX: DDERR_INVALIDSURFACETYPE */
3376
3377 switch (flags)
3378 {
3379 case WINEDDGFS_CANFLIP:
3380 case WINEDDGFS_ISFLIPDONE:
3381 return WINED3D_OK;
3382
3383 default:
3384 return WINED3DERR_INVALIDCALL;
3385 }
3386}
3387
3388HRESULT CDECL wined3d_surface_is_lost(const struct wined3d_surface *surface)
3389{
3390 TRACE("surface %p.\n", surface);
3391
3392 /* D3D8 and 9 loose full devices, ddraw only surfaces. */
3393 return surface->flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
3394}
3395
3396HRESULT CDECL wined3d_surface_restore(struct wined3d_surface *surface)
3397{
3398 TRACE("surface %p.\n", surface);
3399
3400 surface->flags &= ~SFLAG_LOST;
3401 return WINED3D_OK;
3402}
3403
3404void CDECL wined3d_surface_set_palette(struct wined3d_surface *surface, struct wined3d_palette *palette)
3405{
3406 TRACE("surface %p, palette %p.\n", surface, palette);
3407
3408 if (surface->palette == palette)
3409 {
3410 TRACE("Nop palette change.\n");
3411 return;
3412 }
3413
3414 if (surface->palette && (surface->resource.usage & WINED3DUSAGE_RENDERTARGET))
3415 surface->palette->flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
3416
3417 surface->palette = palette;
3418
3419 if (palette)
3420 {
3421 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
3422 palette->flags |= WINEDDPCAPS_PRIMARYSURFACE;
3423
3424 surface->surface_ops->surface_realize_palette(surface);
3425 }
3426}
3427
3428HRESULT CDECL wined3d_surface_set_color_key(struct wined3d_surface *surface,
3429 DWORD flags, const struct wined3d_color_key *color_key)
3430{
3431 TRACE("surface %p, flags %#x, color_key %p.\n", surface, flags, color_key);
3432
3433 if (flags & WINEDDCKEY_COLORSPACE)
3434 {
3435 FIXME(" colorkey value not supported (%08x) !\n", flags);
3436 return WINED3DERR_INVALIDCALL;
3437 }
3438
3439 /* Dirtify the surface, but only if a key was changed. */
3440 if (color_key)
3441 {
3442 switch (flags & ~WINEDDCKEY_COLORSPACE)
3443 {
3444 case WINEDDCKEY_DESTBLT:
3445 surface->dst_blt_color_key = *color_key;
3446 surface->CKeyFlags |= WINEDDSD_CKDESTBLT;
3447 break;
3448
3449 case WINEDDCKEY_DESTOVERLAY:
3450 surface->dst_overlay_color_key = *color_key;
3451 surface->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
3452 break;
3453
3454 case WINEDDCKEY_SRCOVERLAY:
3455 surface->src_overlay_color_key = *color_key;
3456 surface->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
3457 break;
3458
3459 case WINEDDCKEY_SRCBLT:
3460 surface->src_blt_color_key = *color_key;
3461 surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
3462 break;
3463 }
3464 }
3465 else
3466 {
3467 switch (flags & ~WINEDDCKEY_COLORSPACE)
3468 {
3469 case WINEDDCKEY_DESTBLT:
3470 surface->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
3471 break;
3472
3473 case WINEDDCKEY_DESTOVERLAY:
3474 surface->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
3475 break;
3476
3477 case WINEDDCKEY_SRCOVERLAY:
3478 surface->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
3479 break;
3480
3481 case WINEDDCKEY_SRCBLT:
3482 surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
3483 break;
3484 }
3485 }
3486
3487 return WINED3D_OK;
3488}
3489
3490struct wined3d_palette * CDECL wined3d_surface_get_palette(const struct wined3d_surface *surface)
3491{
3492 TRACE("surface %p.\n", surface);
3493
3494 return surface->palette;
3495}
3496
3497DWORD CDECL wined3d_surface_get_pitch(const struct wined3d_surface *surface)
3498{
3499 const struct wined3d_format *format = surface->resource.format;
3500 DWORD pitch;
3501
3502 TRACE("surface %p.\n", surface);
3503
3504 if (surface->pitch)
3505 return surface->pitch;
3506
3507 if (format->flags & WINED3DFMT_FLAG_BLOCKS)
3508 {
3509 /* Since compressed formats are block based, pitch means the amount of
3510 * bytes to the next row of block rather than the next row of pixels. */
3511 UINT row_block_count = (surface->resource.width + format->block_width - 1) / format->block_width;
3512 pitch = row_block_count * format->block_byte_count;
3513 }
3514 else
3515 {
3516 unsigned char alignment = surface->resource.device->surface_alignment;
3517 pitch = surface->resource.format->byte_count * surface->resource.width; /* Bytes / row */
3518 pitch = (pitch + alignment - 1) & ~(alignment - 1);
3519 }
3520
3521 TRACE("Returning %u.\n", pitch);
3522
3523 return pitch;
3524}
3525
3526HRESULT CDECL wined3d_surface_set_mem(struct wined3d_surface *surface, void *mem, UINT pitch)
3527{
3528#ifndef VBOX_WITH_WDDM
3529 TRACE("surface %p, mem %p.\n", surface, mem);
3530
3531 if (surface->resource.map_count || (surface->flags & SFLAG_DCINUSE))
3532 {
3533 WARN("Surface is mapped or the DC is in use.\n");
3534 return WINED3DERR_INVALIDCALL;
3535 }
3536
3537 /* Render targets depend on their hdc, and we can't create an hdc on a user pointer. */
3538 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
3539 {
3540 ERR("Not supported on render targets.\n");
3541 return WINED3DERR_INVALIDCALL;
3542 }
3543
3544 if (mem && mem != surface->resource.allocatedMemory)
3545 {
3546 void *release = NULL;
3547
3548 /* Do I have to copy the old surface content? */
3549 if (surface->flags & SFLAG_DIBSECTION)
3550 {
3551 DeleteDC(surface->hDC);
3552 DeleteObject(surface->dib.DIBsection);
3553 surface->dib.bitmap_data = NULL;
3554 surface->resource.allocatedMemory = NULL;
3555 surface->hDC = NULL;
3556 surface->flags &= ~SFLAG_DIBSECTION;
3557 }
3558 else if (!(surface->flags & SFLAG_USERPTR))
3559 {
3560 release = surface->resource.heapMemory;
3561 surface->resource.heapMemory = NULL;
3562 }
3563 surface->resource.allocatedMemory = mem;
3564 surface->flags |= SFLAG_USERPTR;
3565
3566 /* Now the surface memory is most up do date. Invalidate drawable and texture. */
3567 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
3568
3569 /* For client textures OpenGL has to be notified. */
3570 if (surface->flags & SFLAG_CLIENT)
3571 surface_release_client_storage(surface);
3572
3573 /* Now free the old memory if any. */
3574 HeapFree(GetProcessHeap(), 0, release);
3575 }
3576 else if (surface->flags & SFLAG_USERPTR)
3577 {
3578 /* HeapMemory should be NULL already. */
3579 if (surface->resource.heapMemory)
3580 ERR("User pointer surface has heap memory allocated.\n");
3581
3582 if (!mem)
3583 {
3584 surface->resource.allocatedMemory = NULL;
3585 surface->flags &= ~(SFLAG_USERPTR | SFLAG_INSYSMEM);
3586
3587 if (surface->flags & SFLAG_CLIENT)
3588 surface_release_client_storage(surface);
3589
3590 surface_prepare_system_memory(surface);
3591 }
3592
3593 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
3594 }
3595
3596 surface->pitch = pitch;
3597
3598 return WINED3D_OK;
3599#else
3600 ERR("unsupported!");
3601 return E_FAIL;
3602#endif
3603}
3604
3605HRESULT CDECL wined3d_surface_set_overlay_position(struct wined3d_surface *surface, LONG x, LONG y)
3606{
3607 LONG w, h;
3608
3609 TRACE("surface %p, x %d, y %d.\n", surface, x, y);
3610
3611 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3612 {
3613 WARN("Not an overlay surface.\n");
3614 return WINEDDERR_NOTAOVERLAYSURFACE;
3615 }
3616
3617 w = surface->overlay_destrect.right - surface->overlay_destrect.left;
3618 h = surface->overlay_destrect.bottom - surface->overlay_destrect.top;
3619 surface->overlay_destrect.left = x;
3620 surface->overlay_destrect.top = y;
3621 surface->overlay_destrect.right = x + w;
3622 surface->overlay_destrect.bottom = y + h;
3623
3624 surface_draw_overlay(surface);
3625
3626 return WINED3D_OK;
3627}
3628
3629HRESULT CDECL wined3d_surface_get_overlay_position(const struct wined3d_surface *surface, LONG *x, LONG *y)
3630{
3631 TRACE("surface %p, x %p, y %p.\n", surface, x, y);
3632
3633 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3634 {
3635 TRACE("Not an overlay surface.\n");
3636 return WINEDDERR_NOTAOVERLAYSURFACE;
3637 }
3638
3639 if (!surface->overlay_dest)
3640 {
3641 TRACE("Overlay not visible.\n");
3642 *x = 0;
3643 *y = 0;
3644 return WINEDDERR_OVERLAYNOTVISIBLE;
3645 }
3646
3647 *x = surface->overlay_destrect.left;
3648 *y = surface->overlay_destrect.top;
3649
3650 TRACE("Returning position %d, %d.\n", *x, *y);
3651
3652 return WINED3D_OK;
3653}
3654
3655HRESULT CDECL wined3d_surface_update_overlay_z_order(struct wined3d_surface *surface,
3656 DWORD flags, struct wined3d_surface *ref)
3657{
3658 FIXME("surface %p, flags %#x, ref %p stub!\n", surface, flags, ref);
3659
3660 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3661 {
3662 TRACE("Not an overlay surface.\n");
3663 return WINEDDERR_NOTAOVERLAYSURFACE;
3664 }
3665
3666 return WINED3D_OK;
3667}
3668
3669HRESULT CDECL wined3d_surface_update_overlay(struct wined3d_surface *surface, const RECT *src_rect,
3670 struct wined3d_surface *dst_surface, const RECT *dst_rect, DWORD flags, const WINEDDOVERLAYFX *fx)
3671{
3672 TRACE("surface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
3673 surface, wine_dbgstr_rect(src_rect), dst_surface, wine_dbgstr_rect(dst_rect), flags, fx);
3674
3675 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3676 {
3677 WARN("Not an overlay surface.\n");
3678 return WINEDDERR_NOTAOVERLAYSURFACE;
3679 }
3680 else if (!dst_surface)
3681 {
3682 WARN("Dest surface is NULL.\n");
3683 return WINED3DERR_INVALIDCALL;
3684 }
3685
3686 if (src_rect)
3687 {
3688 surface->overlay_srcrect = *src_rect;
3689 }
3690 else
3691 {
3692 surface->overlay_srcrect.left = 0;
3693 surface->overlay_srcrect.top = 0;
3694 surface->overlay_srcrect.right = surface->resource.width;
3695 surface->overlay_srcrect.bottom = surface->resource.height;
3696 }
3697
3698 if (dst_rect)
3699 {
3700 surface->overlay_destrect = *dst_rect;
3701 }
3702 else
3703 {
3704 surface->overlay_destrect.left = 0;
3705 surface->overlay_destrect.top = 0;
3706 surface->overlay_destrect.right = dst_surface ? dst_surface->resource.width : 0;
3707 surface->overlay_destrect.bottom = dst_surface ? dst_surface->resource.height : 0;
3708 }
3709
3710 if (surface->overlay_dest && (surface->overlay_dest != dst_surface || flags & WINEDDOVER_HIDE))
3711 {
3712 surface->overlay_dest = NULL;
3713 list_remove(&surface->overlay_entry);
3714 }
3715
3716 if (flags & WINEDDOVER_SHOW)
3717 {
3718 if (surface->overlay_dest != dst_surface)
3719 {
3720 surface->overlay_dest = dst_surface;
3721 list_add_tail(&dst_surface->overlays, &surface->overlay_entry);
3722 }
3723 }
3724 else if (flags & WINEDDOVER_HIDE)
3725 {
3726 /* tests show that the rectangles are erased on hide */
3727 surface->overlay_srcrect.left = 0; surface->overlay_srcrect.top = 0;
3728 surface->overlay_srcrect.right = 0; surface->overlay_srcrect.bottom = 0;
3729 surface->overlay_destrect.left = 0; surface->overlay_destrect.top = 0;
3730 surface->overlay_destrect.right = 0; surface->overlay_destrect.bottom = 0;
3731 surface->overlay_dest = NULL;
3732 }
3733
3734 surface_draw_overlay(surface);
3735
3736 return WINED3D_OK;
3737}
3738
3739HRESULT CDECL wined3d_surface_update_desc(struct wined3d_surface *surface,
3740 UINT width, UINT height, enum wined3d_format_id format_id,
3741 enum wined3d_multisample_type multisample_type, UINT multisample_quality)
3742{
3743 struct wined3d_device *device = surface->resource.device;
3744 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
3745 const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
3746 UINT resource_size = wined3d_format_calculate_size(format, device->surface_alignment, width, height);
3747
3748 TRACE("surface %p, width %u, height %u, format %s, multisample_type %#x, multisample_quality %u.\n",
3749 surface, width, height, debug_d3dformat(format_id), multisample_type, multisample_type);
3750
3751 if (!resource_size)
3752 return WINED3DERR_INVALIDCALL;
3753
3754 if (device->d3d_initialized)
3755 surface->resource.resource_ops->resource_unload(&surface->resource);
3756
3757 if (surface->flags & SFLAG_DIBSECTION)
3758 {
3759 DeleteDC(surface->hDC);
3760 DeleteObject(surface->dib.DIBsection);
3761 surface->dib.bitmap_data = NULL;
3762 surface->flags &= ~SFLAG_DIBSECTION;
3763 }
3764
3765 surface->flags &= ~(SFLAG_LOCATIONS | SFLAG_USERPTR);
3766 surface->resource.allocatedMemory = NULL;
3767 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
3768 surface->resource.heapMemory = NULL;
3769
3770 surface->resource.width = width;
3771 surface->resource.height = height;
3772 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
3773 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
3774 {
3775 surface->pow2Width = width;
3776 surface->pow2Height = height;
3777 }
3778 else
3779 {
3780 surface->pow2Width = surface->pow2Height = 1;
3781 while (surface->pow2Width < width)
3782 surface->pow2Width <<= 1;
3783 while (surface->pow2Height < height)
3784 surface->pow2Height <<= 1;
3785 }
3786
3787 if (surface->pow2Width != width || surface->pow2Height != height)
3788 surface->flags |= SFLAG_NONPOW2;
3789 else
3790 surface->flags &= ~SFLAG_NONPOW2;
3791
3792 surface->resource.format = format;
3793 surface->resource.multisample_type = multisample_type;
3794 surface->resource.multisample_quality = multisample_quality;
3795 surface->resource.size = resource_size;
3796
3797 if (!surface_init_sysmem(surface))
3798 return E_OUTOFMEMORY;
3799
3800 return WINED3D_OK;
3801}
3802
3803static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst,
3804 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3805{
3806 unsigned short *dst_s;
3807 const float *src_f;
3808 unsigned int x, y;
3809
3810 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3811
3812 for (y = 0; y < h; ++y)
3813 {
3814 src_f = (const float *)(src + y * pitch_in);
3815 dst_s = (unsigned short *) (dst + y * pitch_out);
3816 for (x = 0; x < w; ++x)
3817 {
3818 dst_s[x] = float_32_to_16(src_f + x);
3819 }
3820 }
3821}
3822
3823static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
3824 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3825{
3826 static const unsigned char convert_5to8[] =
3827 {
3828 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
3829 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
3830 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
3831 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
3832 };
3833 static const unsigned char convert_6to8[] =
3834 {
3835 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
3836 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
3837 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
3838 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
3839 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
3840 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
3841 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
3842 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
3843 };
3844 unsigned int x, y;
3845
3846 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3847
3848 for (y = 0; y < h; ++y)
3849 {
3850 const WORD *src_line = (const WORD *)(src + y * pitch_in);
3851 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3852 for (x = 0; x < w; ++x)
3853 {
3854 WORD pixel = src_line[x];
3855 dst_line[x] = 0xff000000
3856 | convert_5to8[(pixel & 0xf800) >> 11] << 16
3857 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
3858 | convert_5to8[(pixel & 0x001f)];
3859 }
3860 }
3861}
3862
3863/* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
3864 * in both cases we're just setting the X / Alpha channel to 0xff. */
3865static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
3866 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3867{
3868 unsigned int x, y;
3869
3870 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3871
3872 for (y = 0; y < h; ++y)
3873 {
3874 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
3875 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3876
3877 for (x = 0; x < w; ++x)
3878 {
3879 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
3880 }
3881 }
3882}
3883
3884static inline BYTE cliptobyte(int x)
3885{
3886 return (BYTE)((x < 0) ? 0 : ((x > 255) ? 255 : x));
3887}
3888
3889static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
3890 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3891{
3892 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
3893 unsigned int x, y;
3894
3895 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3896
3897 for (y = 0; y < h; ++y)
3898 {
3899 const BYTE *src_line = src + y * pitch_in;
3900 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3901 for (x = 0; x < w; ++x)
3902 {
3903 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3904 * C = Y - 16; D = U - 128; E = V - 128;
3905 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3906 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3907 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3908 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3909 * U and V are shared between the pixels. */
3910 if (!(x & 1)) /* For every even pixel, read new U and V. */
3911 {
3912 d = (int) src_line[1] - 128;
3913 e = (int) src_line[3] - 128;
3914 r2 = 409 * e + 128;
3915 g2 = - 100 * d - 208 * e + 128;
3916 b2 = 516 * d + 128;
3917 }
3918 c2 = 298 * ((int) src_line[0] - 16);
3919 dst_line[x] = 0xff000000
3920 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
3921 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
3922 | cliptobyte((c2 + b2) >> 8); /* blue */
3923 /* Scale RGB values to 0..255 range,
3924 * then clip them if still not in range (may be negative),
3925 * then shift them within DWORD if necessary. */
3926 src_line += 2;
3927 }
3928 }
3929}
3930
3931static void convert_yuy2_r5g6b5(const BYTE *src, BYTE *dst,
3932 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3933{
3934 unsigned int x, y;
3935 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
3936
3937 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
3938
3939 for (y = 0; y < h; ++y)
3940 {
3941 const BYTE *src_line = src + y * pitch_in;
3942 WORD *dst_line = (WORD *)(dst + y * pitch_out);
3943 for (x = 0; x < w; ++x)
3944 {
3945 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3946 * C = Y - 16; D = U - 128; E = V - 128;
3947 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3948 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3949 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3950 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3951 * U and V are shared between the pixels. */
3952 if (!(x & 1)) /* For every even pixel, read new U and V. */
3953 {
3954 d = (int) src_line[1] - 128;
3955 e = (int) src_line[3] - 128;
3956 r2 = 409 * e + 128;
3957 g2 = - 100 * d - 208 * e + 128;
3958 b2 = 516 * d + 128;
3959 }
3960 c2 = 298 * ((int) src_line[0] - 16);
3961 dst_line[x] = (cliptobyte((c2 + r2) >> 8) >> 3) << 11 /* red */
3962 | (cliptobyte((c2 + g2) >> 8) >> 2) << 5 /* green */
3963 | (cliptobyte((c2 + b2) >> 8) >> 3); /* blue */
3964 /* Scale RGB values to 0..255 range,
3965 * then clip them if still not in range (may be negative),
3966 * then shift them within DWORD if necessary. */
3967 src_line += 2;
3968 }
3969 }
3970}
3971
3972struct d3dfmt_converter_desc
3973{
3974 enum wined3d_format_id from, to;
3975 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
3976};
3977
3978static const struct d3dfmt_converter_desc converters[] =
3979{
3980 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
3981 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
3982 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
3983 {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_B8G8R8A8_UNORM, convert_a8r8g8b8_x8r8g8b8},
3984 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
3985 {WINED3DFMT_YUY2, WINED3DFMT_B5G6R5_UNORM, convert_yuy2_r5g6b5},
3986};
3987
3988static inline const struct d3dfmt_converter_desc *find_converter(enum wined3d_format_id from,
3989 enum wined3d_format_id to)
3990{
3991 unsigned int i;
3992
3993 for (i = 0; i < (sizeof(converters) / sizeof(*converters)); ++i)
3994 {
3995 if (converters[i].from == from && converters[i].to == to)
3996 return &converters[i];
3997 }
3998
3999 return NULL;
4000}
4001
4002/*****************************************************************************
4003 * surface_convert_format
4004 *
4005 * Creates a duplicate of a surface in a different format. Is used by Blt to
4006 * blit between surfaces with different formats.
4007 *
4008 * Parameters
4009 * source: Source surface
4010 * fmt: Requested destination format
4011 *
4012 *****************************************************************************/
4013static struct wined3d_surface *surface_convert_format(struct wined3d_surface *source, enum wined3d_format_id to_fmt)
4014{
4015 struct wined3d_map_desc src_map, dst_map;
4016 const struct d3dfmt_converter_desc *conv;
4017 struct wined3d_surface *ret = NULL;
4018 HRESULT hr;
4019
4020 conv = find_converter(source->resource.format->id, to_fmt);
4021 if (!conv)
4022 {
4023 FIXME("Cannot find a conversion function from format %s to %s.\n",
4024 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
4025 return NULL;
4026 }
4027
4028 /* FIXME: Multisampled conversion? */
4029#ifdef VBOX_WITH_WDDM
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 , NULL, NULL
4034 )))
4035#else
4036 if (FAILED(hr = wined3d_surface_create(source->resource.device, source->resource.width, source->resource.height,
4037 to_fmt, 0, WINED3D_POOL_SCRATCH, WINED3D_MULTISAMPLE_NONE, 0,
4038 WINED3D_SURFACE_MAPPABLE | WINED3D_SURFACE_DISCARD, NULL, &wined3d_null_parent_ops, &ret)))
4039#endif
4040 {
4041 ERR("Failed to create a destination surface for conversion.\n");
4042 return NULL;
4043 }
4044
4045 memset(&src_map, 0, sizeof(src_map));
4046 memset(&dst_map, 0, sizeof(dst_map));
4047
4048 if (FAILED(hr = wined3d_surface_map(source, &src_map, NULL, WINED3D_MAP_READONLY)))
4049 {
4050 ERR("Failed to lock the source surface.\n");
4051 wined3d_surface_decref(ret);
4052 return NULL;
4053 }
4054 if (FAILED(hr = wined3d_surface_map(ret, &dst_map, NULL, WINED3D_MAP_READONLY)))
4055 {
4056 ERR("Failed to lock the destination surface.\n");
4057 wined3d_surface_unmap(source);
4058 wined3d_surface_decref(ret);
4059 return NULL;
4060 }
4061
4062 conv->convert(src_map.data, dst_map.data, src_map.row_pitch, dst_map.row_pitch,
4063 source->resource.width, source->resource.height);
4064
4065 wined3d_surface_unmap(ret);
4066 wined3d_surface_unmap(source);
4067
4068 return ret;
4069}
4070
4071static HRESULT _Blt_ColorFill(BYTE *buf, unsigned int width, unsigned int height,
4072 unsigned int bpp, UINT pitch, DWORD color)
4073{
4074 BYTE *first;
4075 unsigned int x, y;
4076
4077 /* Do first row */
4078
4079#define COLORFILL_ROW(type) \
4080do { \
4081 type *d = (type *)buf; \
4082 for (x = 0; x < width; ++x) \
4083 d[x] = (type)color; \
4084} while(0)
4085
4086 switch (bpp)
4087 {
4088 case 1:
4089 COLORFILL_ROW(BYTE);
4090 break;
4091
4092 case 2:
4093 COLORFILL_ROW(WORD);
4094 break;
4095
4096 case 3:
4097 {
4098 BYTE *d = buf;
4099 for (x = 0; x < width; ++x, d += 3)
4100 {
4101 d[0] = (color ) & 0xff;
4102 d[1] = (color >> 8) & 0xff;
4103 d[2] = (color >> 16) & 0xff;
4104 }
4105 break;
4106 }
4107 case 4:
4108 COLORFILL_ROW(DWORD);
4109 break;
4110
4111 default:
4112 FIXME("Color fill not implemented for bpp %u!\n", bpp * 8);
4113 return WINED3DERR_NOTAVAILABLE;
4114 }
4115
4116#undef COLORFILL_ROW
4117
4118 /* Now copy first row. */
4119 first = buf;
4120 for (y = 1; y < height; ++y)
4121 {
4122 buf += pitch;
4123 memcpy(buf, first, width * bpp);
4124 }
4125
4126 return WINED3D_OK;
4127}
4128
4129struct wined3d_surface * CDECL wined3d_surface_from_resource(struct wined3d_resource *resource)
4130{
4131 return surface_from_resource(resource);
4132}
4133
4134HRESULT CDECL wined3d_surface_unmap(struct wined3d_surface *surface)
4135{
4136 TRACE("surface %p.\n", surface);
4137
4138 if (!surface->resource.map_count)
4139 {
4140 WARN("Trying to unmap unmapped surface.\n");
4141 return WINEDDERR_NOTLOCKED;
4142 }
4143 --surface->resource.map_count;
4144
4145 surface->surface_ops->surface_unmap(surface);
4146
4147#ifdef VBOX_WITH_WDDM
4148 surface_shrc_unlock(surface);
4149#endif
4150
4151 return WINED3D_OK;
4152}
4153
4154HRESULT CDECL wined3d_surface_map(struct wined3d_surface *surface,
4155 struct wined3d_map_desc *map_desc, const RECT *rect, DWORD flags)
4156{
4157 const struct wined3d_format *format = surface->resource.format;
4158
4159 TRACE("surface %p, map_desc %p, rect %s, flags %#x.\n",
4160 surface, map_desc, wine_dbgstr_rect(rect), flags);
4161
4162 if (surface->resource.map_count)
4163 {
4164 WARN("Surface is already mapped.\n");
4165 return WINED3DERR_INVALIDCALL;
4166 }
4167
4168 if ((format->flags & WINED3DFMT_FLAG_BLOCKS) && rect
4169 && !surface_check_block_align(surface, rect))
4170 {
4171 WARN("Map rect %s is misaligned for %ux%u blocks.\n",
4172 wine_dbgstr_rect(rect), format->block_width, format->block_height);
4173
4174 if (surface->resource.pool == WINED3D_POOL_DEFAULT)
4175 return WINED3DERR_INVALIDCALL;
4176 }
4177
4178#ifdef VBOX_WITH_WDDM
4179 surface_shrc_lock(surface);
4180#endif
4181
4182 ++surface->resource.map_count;
4183
4184 if (!(surface->flags & SFLAG_LOCKABLE))
4185 WARN("Trying to lock unlockable surface.\n");
4186
4187 /* Performance optimization: Count how often a surface is mapped, if it is
4188 * mapped regularly do not throw away the system memory copy. This avoids
4189 * the need to download the surface from OpenGL all the time. The surface
4190 * is still downloaded if the OpenGL texture is changed. */
4191 if (!(surface->flags & SFLAG_DYNLOCK))
4192 {
4193 if (++surface->lockCount > MAXLOCKCOUNT)
4194 {
4195 TRACE("Surface is mapped regularly, not freeing the system memory copy any more.\n");
4196 surface->flags |= SFLAG_DYNLOCK;
4197 }
4198 }
4199
4200 surface->surface_ops->surface_map(surface, rect, flags);
4201
4202 if (format->flags & WINED3DFMT_FLAG_BROKEN_PITCH)
4203 map_desc->row_pitch = surface->resource.width * format->byte_count;
4204 else
4205 map_desc->row_pitch = wined3d_surface_get_pitch(surface);
4206 map_desc->slice_pitch = 0;
4207
4208 if (!rect)
4209 {
4210 map_desc->data = surface->resource.allocatedMemory;
4211 surface->lockedRect.left = 0;
4212 surface->lockedRect.top = 0;
4213 surface->lockedRect.right = surface->resource.width;
4214 surface->lockedRect.bottom = surface->resource.height;
4215 }
4216 else
4217 {
4218 if ((format->flags & (WINED3DFMT_FLAG_BLOCKS | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_BLOCKS)
4219 {
4220 /* Compressed textures are block based, so calculate the offset of
4221 * the block that contains the top-left pixel of the locked rectangle. */
4222 map_desc->data = surface->resource.allocatedMemory
4223 + ((rect->top / format->block_height) * map_desc->row_pitch)
4224 + ((rect->left / format->block_width) * format->block_byte_count);
4225 }
4226 else
4227 {
4228 map_desc->data = surface->resource.allocatedMemory
4229 + (map_desc->row_pitch * rect->top)
4230 + (rect->left * format->byte_count);
4231 }
4232 surface->lockedRect.left = rect->left;
4233 surface->lockedRect.top = rect->top;
4234 surface->lockedRect.right = rect->right;
4235 surface->lockedRect.bottom = rect->bottom;
4236 }
4237
4238 TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface->lockedRect));
4239 TRACE("Returning memory %p, pitch %u.\n", map_desc->data, map_desc->row_pitch);
4240
4241 return WINED3D_OK;
4242}
4243
4244HRESULT CDECL wined3d_surface_getdc(struct wined3d_surface *surface, HDC *dc)
4245{
4246 struct wined3d_map_desc map;
4247 HRESULT hr;
4248
4249 TRACE("surface %p, dc %p.\n", surface, dc);
4250
4251 if (surface->flags & SFLAG_USERPTR)
4252 {
4253 ERR("Not supported on surfaces with application-provided memory.\n");
4254 return WINEDDERR_NODC;
4255 }
4256
4257 /* Give more detailed info for ddraw. */
4258 if (surface->flags & SFLAG_DCINUSE)
4259 return WINEDDERR_DCALREADYCREATED;
4260
4261 /* Can't GetDC if the surface is locked. */
4262 if (surface->resource.map_count)
4263 return WINED3DERR_INVALIDCALL;
4264
4265 /* Create a DIB section if there isn't a dc yet. */
4266 if (!surface->hDC)
4267 {
4268 if (surface->flags & SFLAG_CLIENT)
4269 {
4270 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
4271 surface_release_client_storage(surface);
4272 }
4273 hr = surface_create_dib_section(surface);
4274 if (FAILED(hr))
4275 return WINED3DERR_INVALIDCALL;
4276
4277 /* Use the DIB section from now on if we are not using a PBO. */
4278 if (!(surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM)))
4279 {
4280 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
4281 surface->resource.heapMemory = NULL;
4282 surface->resource.allocatedMemory = surface->dib.bitmap_data;
4283 }
4284 }
4285
4286 /* Map the surface. */
4287 hr = wined3d_surface_map(surface, &map, NULL, 0);
4288 if (FAILED(hr))
4289 {
4290 ERR("Map failed, hr %#x.\n", hr);
4291 return hr;
4292 }
4293
4294 /* Sync the DIB with the PBO. This can't be done earlier because Map()
4295 * activates the allocatedMemory. */
4296#ifdef VBOX_WITH_WINE_FIX_PBOPSM
4297 if ((surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM)) == (SFLAG_PBO | SFLAG_PIN_SYSMEM))
4298#else
4299 if (surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM))
4300#endif
4301 memcpy(surface->dib.bitmap_data, surface->resource.allocatedMemory, surface->resource.size);
4302
4303 if (surface->resource.format->id == WINED3DFMT_P8_UINT
4304 || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
4305 {
4306 /* GetDC on palettized formats is unsupported in D3D9, and the method
4307 * is missing in D3D8, so this should only be used for DX <=7
4308 * surfaces (with non-device palettes). */
4309 const PALETTEENTRY *pal = NULL;
4310
4311 if (surface->palette)
4312 {
4313 pal = surface->palette->palents;
4314 }
4315 else
4316 {
4317 struct wined3d_swapchain *swapchain = surface->resource.device->swapchains[0];
4318 struct wined3d_surface *dds_primary = swapchain->front_buffer;
4319
4320 if (dds_primary && dds_primary->palette)
4321 pal = dds_primary->palette->palents;
4322 }
4323
4324 if (pal)
4325 {
4326 RGBQUAD col[256];
4327 unsigned int i;
4328
4329 for (i = 0; i < 256; ++i)
4330 {
4331 col[i].rgbRed = pal[i].peRed;
4332 col[i].rgbGreen = pal[i].peGreen;
4333 col[i].rgbBlue = pal[i].peBlue;
4334 col[i].rgbReserved = 0;
4335 }
4336 SetDIBColorTable(surface->hDC, 0, 256, col);
4337 }
4338 }
4339
4340 surface->flags |= SFLAG_DCINUSE;
4341
4342 *dc = surface->hDC;
4343 TRACE("Returning dc %p.\n", *dc);
4344
4345 return WINED3D_OK;
4346}
4347
4348HRESULT CDECL wined3d_surface_releasedc(struct wined3d_surface *surface, HDC dc)
4349{
4350 TRACE("surface %p, dc %p.\n", surface, dc);
4351
4352 if (!(surface->flags & SFLAG_DCINUSE))
4353 return WINEDDERR_NODC;
4354
4355 if (surface->hDC != dc)
4356 {
4357 WARN("Application tries to release invalid DC %p, surface DC is %p.\n",
4358 dc, surface->hDC);
4359 return WINEDDERR_NODC;
4360 }
4361
4362 /* Copy the contents of the DIB over to the PBO. */
4363#ifdef VBOX_WITH_WINE_FIX_PBOPSM
4364 if (((surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM)) == (SFLAG_PBO | SFLAG_PIN_SYSMEM)) && surface->resource.allocatedMemory)
4365#else
4366 if ((surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM)) && surface->resource.allocatedMemory)
4367#endif
4368 memcpy(surface->resource.allocatedMemory, surface->dib.bitmap_data, surface->resource.size);
4369
4370 /* We locked first, so unlock now. */
4371 wined3d_surface_unmap(surface);
4372
4373 surface->flags &= ~SFLAG_DCINUSE;
4374
4375 return WINED3D_OK;
4376}
4377
4378HRESULT CDECL wined3d_surface_flip(struct wined3d_surface *surface, struct wined3d_surface *override, DWORD flags)
4379{
4380 TRACE("surface %p, override %p, flags %#x.\n", surface, override, flags);
4381
4382 if (flags)
4383 {
4384 static UINT once;
4385 if (!once++)
4386 FIXME("Ignoring flags %#x.\n", flags);
4387 else
4388 WARN("Ignoring flags %#x.\n", flags);
4389 }
4390
4391 if (surface->swapchain)
4392 {
4393 ERR("Not supported on swapchain surfaces.\n");
4394 return WINEDDERR_NOTFLIPPABLE;
4395 }
4396
4397 flip_surface(surface, override);
4398
4399 /* Update overlays if they're visible. */
4400 if ((surface->resource.usage & WINED3DUSAGE_OVERLAY) && surface->overlay_dest)
4401 return surface_draw_overlay(surface);
4402
4403 return WINED3D_OK;
4404}
4405
4406/* Do not call while under the GL lock. */
4407void surface_internal_preload(struct wined3d_surface *surface, enum WINED3DSRGB srgb)
4408{
4409 struct wined3d_device *device = surface->resource.device;
4410
4411 TRACE("iface %p, srgb %#x.\n", surface, srgb);
4412
4413 if (surface->container)
4414 {
4415 struct wined3d_texture *texture = surface->container;
4416
4417 TRACE("Passing to container (%p).\n", texture);
4418 texture->texture_ops->texture_preload(texture, srgb);
4419 }
4420 else
4421 {
4422 struct wined3d_context *context;
4423
4424 TRACE("(%p) : About to load surface\n", surface);
4425
4426 /* TODO: Use already acquired context when possible. */
4427 context = context_acquire(device, NULL);
4428
4429 surface_load(surface, srgb == SRGB_SRGB);
4430
4431#ifndef VBOX
4432 if (surface->resource.pool == WINED3D_POOL_DEFAULT)
4433 {
4434 /* Tell opengl to try and keep this texture in video ram (well mostly) */
4435 GLclampf tmp;
4436 tmp = 0.9f;
4437 context->gl_info->gl_ops.gl.p_glPrioritizeTextures(1, &surface->texture_name, &tmp);
4438 }
4439#else
4440 /* chromium code on host fails to resolve texture name to texture obj,
4441 * most likely because the texture does not get created until it is bound
4442 * @todo: investigate */
4443#endif
4444 context_release(context);
4445 }
4446}
4447
4448/* Read the framebuffer back into the surface */
4449static void read_from_framebuffer(struct wined3d_surface *surface, const RECT *rect, void *dest, UINT pitch)
4450{
4451 struct wined3d_device *device = surface->resource.device;
4452 const struct wined3d_gl_info *gl_info;
4453 struct wined3d_context *context;
4454 BYTE *mem;
4455 GLint fmt;
4456 GLint type;
4457 BYTE *row, *top, *bottom;
4458 int i;
4459 BOOL bpp;
4460 RECT local_rect;
4461 BOOL srcIsUpsideDown;
4462 GLint rowLen = 0;
4463 GLint skipPix = 0;
4464 GLint skipRow = 0;
4465
4466 context = context_acquire(device, surface);
4467 context_apply_blit_state(context, device);
4468 gl_info = context->gl_info;
4469
4470 /* Select the correct read buffer, and give some debug output.
4471 * There is no need to keep track of the current read buffer or reset it, every part of the code
4472 * that reads sets the read buffer as desired.
4473 */
4474 if (surface_is_offscreen(surface))
4475 {
4476 /* Mapping the primary render target which is not on a swapchain.
4477 * Read from the back buffer. */
4478 TRACE("Mapping offscreen render target.\n");
4479 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
4480 srcIsUpsideDown = TRUE;
4481 }
4482 else
4483 {
4484 /* Onscreen surfaces are always part of a swapchain */
4485 GLenum buffer = surface_get_gl_buffer(surface);
4486 TRACE("Mapping %#x buffer.\n", buffer);
4487 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
4488 checkGLcall("glReadBuffer");
4489 srcIsUpsideDown = FALSE;
4490 }
4491
4492 /* TODO: Get rid of the extra rectangle comparison and construction of a full surface rectangle */
4493 if (!rect)
4494 {
4495 local_rect.left = 0;
4496 local_rect.top = 0;
4497 local_rect.right = surface->resource.width;
4498 local_rect.bottom = surface->resource.height;
4499 }
4500 else
4501 {
4502 local_rect = *rect;
4503 }
4504 /* TODO: Get rid of the extra GetPitch call, LockRect does that too. Cache the pitch */
4505
4506 switch (surface->resource.format->id)
4507 {
4508 case WINED3DFMT_P8_UINT:
4509 {
4510 if (primary_render_target_is_p8(device))
4511 {
4512 /* In case of P8 render targets the index is stored in the alpha component */
4513 fmt = GL_ALPHA;
4514 type = GL_UNSIGNED_BYTE;
4515 mem = dest;
4516 bpp = surface->resource.format->byte_count;
4517 }
4518 else
4519 {
4520 /* GL can't return palettized data, so read ARGB pixels into a
4521 * separate block of memory and convert them into palettized format
4522 * in software. Slow, but if the app means to use palettized render
4523 * targets and locks it...
4524 *
4525 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
4526 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
4527 * for the color channels when palettizing the colors.
4528 */
4529 fmt = GL_RGB;
4530 type = GL_UNSIGNED_BYTE;
4531 pitch *= 3;
4532 mem = HeapAlloc(GetProcessHeap(), 0, surface->resource.size * 3);
4533 if (!mem)
4534 {
4535 ERR("Out of memory\n");
4536 return;
4537 }
4538 bpp = surface->resource.format->byte_count * 3;
4539 }
4540 }
4541 break;
4542
4543 default:
4544 mem = dest;
4545 fmt = surface->resource.format->glFormat;
4546 type = surface->resource.format->glType;
4547 bpp = surface->resource.format->byte_count;
4548 }
4549
4550 if (surface->flags & SFLAG_PBO)
4551 {
4552 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
4553 checkGLcall("glBindBufferARB");
4554 if (mem)
4555 {
4556 ERR("mem not null for pbo -- unexpected\n");
4557 mem = NULL;
4558 }
4559 }
4560
4561 /* Save old pixel store pack state */
4562 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PACK_ROW_LENGTH, &rowLen);
4563 checkGLcall("glGetIntegerv");
4564 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PACK_SKIP_PIXELS, &skipPix);
4565 checkGLcall("glGetIntegerv");
4566 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PACK_SKIP_ROWS, &skipRow);
4567 checkGLcall("glGetIntegerv");
4568
4569 /* Setup pixel store pack state -- to glReadPixels into the correct place */
4570 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, surface->resource.width);
4571 checkGLcall("glPixelStorei");
4572 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_PIXELS, local_rect.left);
4573 checkGLcall("glPixelStorei");
4574 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_ROWS, local_rect.top);
4575 checkGLcall("glPixelStorei");
4576
4577 gl_info->gl_ops.gl.p_glReadPixels(local_rect.left,
4578 !srcIsUpsideDown ? (surface->resource.height - local_rect.bottom) : local_rect.top,
4579 local_rect.right - local_rect.left,
4580 local_rect.bottom - local_rect.top,
4581 fmt, type, mem);
4582 checkGLcall("glReadPixels");
4583
4584 /* Reset previous pixel store pack state */
4585 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, rowLen);
4586 checkGLcall("glPixelStorei");
4587 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_PIXELS, skipPix);
4588 checkGLcall("glPixelStorei");
4589 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_ROWS, skipRow);
4590 checkGLcall("glPixelStorei");
4591
4592 if (surface->flags & SFLAG_PBO)
4593 {
4594 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
4595 checkGLcall("glBindBufferARB");
4596
4597 /* Check if we need to flip the image. If we need to flip use glMapBufferARB
4598 * to get a pointer to it and perform the flipping in software. This is a lot
4599 * faster than calling glReadPixels for each line. In case we want more speed
4600 * we should rerender it flipped in a FBO and read the data back from the FBO. */
4601 if (!srcIsUpsideDown)
4602 {
4603 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
4604 checkGLcall("glBindBufferARB");
4605
4606 mem = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
4607 checkGLcall("glMapBufferARB");
4608 }
4609 }
4610
4611 /* TODO: Merge this with the palettization loop below for P8 targets */
4612 if(!srcIsUpsideDown) {
4613 UINT len, off;
4614 /* glReadPixels returns the image upside down, and there is no way to prevent this.
4615 Flip the lines in software */
4616 len = (local_rect.right - local_rect.left) * bpp;
4617 off = local_rect.left * bpp;
4618
4619 row = HeapAlloc(GetProcessHeap(), 0, len);
4620 if(!row) {
4621 ERR("Out of memory\n");
4622 if (surface->resource.format->id == WINED3DFMT_P8_UINT)
4623 HeapFree(GetProcessHeap(), 0, mem);
4624 return;
4625 }
4626
4627 top = mem + pitch * local_rect.top;
4628 bottom = mem + pitch * (local_rect.bottom - 1);
4629 for(i = 0; i < (local_rect.bottom - local_rect.top) / 2; i++) {
4630 memcpy(row, top + off, len);
4631 memcpy(top + off, bottom + off, len);
4632 memcpy(bottom + off, row, len);
4633 top += pitch;
4634 bottom -= pitch;
4635 }
4636 HeapFree(GetProcessHeap(), 0, row);
4637
4638 /* Unmap the temp PBO buffer */
4639 if (surface->flags & SFLAG_PBO)
4640 {
4641 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
4642 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
4643 }
4644 }
4645
4646 context_release(context);
4647
4648 /* For P8 textures we need to perform an inverse palette lookup. This is
4649 * done by searching for a palette index which matches the RGB value.
4650 * Note this isn't guaranteed to work when there are multiple entries for
4651 * the same color but we have no choice. In case of P8 render targets,
4652 * the index is stored in the alpha component so no conversion is needed. */
4653 if (surface->resource.format->id == WINED3DFMT_P8_UINT && !primary_render_target_is_p8(device))
4654 {
4655 const PALETTEENTRY *pal = NULL;
4656 DWORD width = pitch / 3;
4657 int x, y, c;
4658
4659 if (surface->palette)
4660 {
4661 pal = surface->palette->palents;
4662 }
4663 else
4664 {
4665 ERR("Palette is missing, cannot perform inverse palette lookup\n");
4666 HeapFree(GetProcessHeap(), 0, mem);
4667 return;
4668 }
4669
4670 for(y = local_rect.top; y < local_rect.bottom; y++) {
4671 for(x = local_rect.left; x < local_rect.right; x++) {
4672 /* start lines pixels */
4673 const BYTE *blue = mem + y * pitch + x * (sizeof(BYTE) * 3);
4674 const BYTE *green = blue + 1;
4675 const BYTE *red = green + 1;
4676
4677 for(c = 0; c < 256; c++) {
4678 if(*red == pal[c].peRed &&
4679 *green == pal[c].peGreen &&
4680 *blue == pal[c].peBlue)
4681 {
4682 *((BYTE *) dest + y * width + x) = c;
4683 break;
4684 }
4685 }
4686 }
4687 }
4688 HeapFree(GetProcessHeap(), 0, mem);
4689 }
4690}
4691
4692/* Read the framebuffer contents into a texture. Note that this function
4693 * doesn't do any kind of flipping. Using this on an onscreen surface will
4694 * result in a flipped D3D texture. */
4695void surface_load_fb_texture(struct wined3d_surface *surface, BOOL srgb)
4696{
4697 struct wined3d_device *device = surface->resource.device;
4698 const struct wined3d_gl_info *gl_info;
4699 struct wined3d_context *context;
4700
4701 context = context_acquire(device, surface);
4702 gl_info = context->gl_info;
4703 device_invalidate_state(device, STATE_FRAMEBUFFER);
4704
4705 surface_prepare_texture(surface, context, srgb);
4706 surface_bind_and_dirtify(surface, context, srgb);
4707
4708 TRACE("Reading back offscreen render target %p.\n", surface);
4709
4710 if (surface_is_offscreen(surface))
4711 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
4712 else
4713 gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(surface));
4714 checkGLcall("glReadBuffer");
4715
4716 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(surface->texture_target, surface->texture_level,
4717 0, 0, 0, 0, surface->resource.width, surface->resource.height);
4718 checkGLcall("glCopyTexSubImage2D");
4719
4720 context_release(context);
4721}
4722
4723/* Context activation is done by the caller. */
4724static void surface_prepare_texture_internal(struct wined3d_surface *surface,
4725 struct wined3d_context *context, BOOL srgb)
4726{
4727 DWORD alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED;
4728 enum wined3d_conversion_type convert;
4729 struct wined3d_format format;
4730
4731 if (surface->flags & alloc_flag) return;
4732
4733 d3dfmt_get_conv(surface, TRUE, TRUE, &format, &convert);
4734 if (convert != WINED3D_CT_NONE || format.convert)
4735 surface->flags |= SFLAG_CONVERTED;
4736 else surface->flags &= ~SFLAG_CONVERTED;
4737
4738 surface_bind_and_dirtify(surface, context, srgb);
4739 surface_allocate_surface(surface, context->gl_info, &format, srgb);
4740 surface->flags |= alloc_flag;
4741}
4742
4743/* Context activation is done by the caller. */
4744void surface_prepare_texture(struct wined3d_surface *surface, struct wined3d_context *context, BOOL srgb)
4745{
4746 if (surface->container)
4747 {
4748 struct wined3d_texture *texture = surface->container;
4749 UINT sub_count = texture->level_count * texture->layer_count;
4750 UINT i;
4751
4752 TRACE("surface %p is a subresource of texture %p.\n", surface, texture);
4753
4754 for (i = 0; i < sub_count; ++i)
4755 {
4756 struct wined3d_surface *s = surface_from_resource(texture->sub_resources[i]);
4757 surface_prepare_texture_internal(s, context, srgb);
4758 }
4759
4760 return;
4761 }
4762
4763 surface_prepare_texture_internal(surface, context, srgb);
4764}
4765
4766void surface_prepare_rb(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info, BOOL multisample)
4767{
4768 if (multisample)
4769 {
4770 if (surface->rb_multisample)
4771 return;
4772
4773 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_multisample);
4774 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_multisample);
4775 gl_info->fbo_ops.glRenderbufferStorageMultisample(GL_RENDERBUFFER, surface->resource.multisample_type,
4776 surface->resource.format->glInternal, surface->pow2Width, surface->pow2Height);
4777 TRACE("Created multisample rb %u.\n", surface->rb_multisample);
4778 }
4779 else
4780 {
4781 if (surface->rb_resolved)
4782 return;
4783
4784 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_resolved);
4785 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_resolved);
4786 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, surface->resource.format->glInternal,
4787 surface->pow2Width, surface->pow2Height);
4788 TRACE("Created resolved rb %u.\n", surface->rb_resolved);
4789 }
4790}
4791
4792static void flush_to_framebuffer_drawpixels(struct wined3d_surface *surface,
4793 const RECT *rect, GLenum fmt, GLenum type, UINT bpp, const BYTE *mem)
4794{
4795 struct wined3d_device *device = surface->resource.device;
4796 UINT pitch = wined3d_surface_get_pitch(surface);
4797 const struct wined3d_gl_info *gl_info;
4798 struct wined3d_context *context;
4799 RECT local_rect;
4800 UINT w, h;
4801
4802 surface_get_rect(surface, rect, &local_rect);
4803
4804 mem += local_rect.top * pitch + local_rect.left * bpp;
4805 w = local_rect.right - local_rect.left;
4806 h = local_rect.bottom - local_rect.top;
4807
4808 /* Activate the correct context for the render target */
4809 context = context_acquire(device, surface);
4810 context_apply_blit_state(context, device);
4811 gl_info = context->gl_info;
4812
4813 if (!surface_is_offscreen(surface))
4814 {
4815 GLenum buffer = surface_get_gl_buffer(surface);
4816 TRACE("Unlocking %#x buffer.\n", buffer);
4817 context_set_draw_buffer(context, buffer);
4818
4819#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
4820 surface_translate_drawable_coords(surface, context->win_handle, &local_rect);
4821#else
4822 surface_translate_drawable_coords(surface, context->swapchain->win_handle, &local_rect);
4823#endif
4824 gl_info->gl_ops.gl.p_glPixelZoom(1.0f, -1.0f);
4825 }
4826 else
4827 {
4828 /* Primary offscreen render target */
4829 TRACE("Offscreen render target.\n");
4830 context_set_draw_buffer(context, device->offscreenBuffer);
4831
4832 gl_info->gl_ops.gl.p_glPixelZoom(1.0f, 1.0f);
4833 }
4834
4835 gl_info->gl_ops.gl.p_glRasterPos3i(local_rect.left, local_rect.top, 1);
4836 checkGLcall("glRasterPos3i");
4837
4838 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
4839 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, surface->resource.width);
4840
4841 if (surface->flags & SFLAG_PBO)
4842 {
4843 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
4844 checkGLcall("glBindBufferARB");
4845 }
4846
4847 gl_info->gl_ops.gl.p_glDrawPixels(w, h, fmt, type, mem);
4848 checkGLcall("glDrawPixels");
4849
4850 if (surface->flags & SFLAG_PBO)
4851 {
4852 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
4853 checkGLcall("glBindBufferARB");
4854 }
4855
4856 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
4857 checkGLcall("glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)");
4858
4859 if (wined3d_settings.strict_draw_ordering
4860 || (surface->swapchain && surface->swapchain->front_buffer == surface))
4861 gl_info->gl_ops.gl.p_glFlush();
4862
4863 context_release(context);
4864}
4865
4866static BOOL color_in_range(const struct wined3d_color_key *color_key, DWORD color)
4867{
4868 /* FIXME: Is this really how color keys are supposed to work? I think it
4869 * makes more sense to compare the individual channels. */
4870 return color >= color_key->color_space_low_value
4871 && color <= color_key->color_space_high_value;
4872}
4873
4874void d3dfmt_p8_init_palette(const struct wined3d_surface *surface, BYTE table[256][4], BOOL colorkey)
4875{
4876 const struct wined3d_device *device = surface->resource.device;
4877 const struct wined3d_palette *pal = surface->palette;
4878 BOOL index_in_alpha = FALSE;
4879 unsigned int i;
4880
4881 /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
4882 * Reading back the RGB output each lockrect (each frame as they lock the whole screen)
4883 * is slow. Further RGB->P8 conversion is not possible because palettes can have
4884 * duplicate entries. Store the color key in the unused alpha component to speed the
4885 * download up and to make conversion unneeded. */
4886 index_in_alpha = primary_render_target_is_p8(device);
4887
4888 if (!pal)
4889 {
4890 FIXME("No palette set.\n");
4891 if (index_in_alpha)
4892 {
4893 /* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
4894 * there's no palette at this time. */
4895 for (i = 0; i < 256; i++) table[i][3] = i;
4896 }
4897 }
4898 else
4899 {
4900 TRACE("Using surface palette %p\n", pal);
4901 /* Get the surface's palette */
4902 for (i = 0; i < 256; ++i)
4903 {
4904 table[i][0] = pal->palents[i].peRed;
4905 table[i][1] = pal->palents[i].peGreen;
4906 table[i][2] = pal->palents[i].peBlue;
4907
4908 /* When index_in_alpha is set the palette index is stored in the
4909 * alpha component. In case of a readback we can then read
4910 * GL_ALPHA. Color keying is handled in BltOverride using a
4911 * GL_ALPHA_TEST using GL_NOT_EQUAL. In case of index_in_alpha the
4912 * color key itself is passed to glAlphaFunc in other cases the
4913 * alpha component of pixels that should be masked away is set to 0. */
4914 if (index_in_alpha)
4915 table[i][3] = i;
4916 else if (colorkey && color_in_range(&surface->src_blt_color_key, i))
4917 table[i][3] = 0x00;
4918 else if (pal->flags & WINEDDPCAPS_ALPHA)
4919 table[i][3] = pal->palents[i].peFlags;
4920 else
4921 table[i][3] = 0xff;
4922 }
4923 }
4924}
4925
4926static HRESULT d3dfmt_convert_surface(const BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height,
4927 UINT outpitch, enum wined3d_conversion_type conversion_type, struct wined3d_surface *surface)
4928{
4929 const BYTE *source;
4930 BYTE *dest;
4931
4932 TRACE("src %p, dst %p, pitch %u, width %u, height %u, outpitch %u, conversion_type %#x, surface %p.\n",
4933 src, dst, pitch, width, height, outpitch, conversion_type, surface);
4934
4935 switch (conversion_type)
4936 {
4937 case WINED3D_CT_NONE:
4938 {
4939 memcpy(dst, src, pitch * height);
4940 break;
4941 }
4942
4943 case WINED3D_CT_PALETTED:
4944 case WINED3D_CT_PALETTED_CK:
4945 {
4946 BYTE table[256][4];
4947 unsigned int x, y;
4948
4949 d3dfmt_p8_init_palette(surface, table, (conversion_type == WINED3D_CT_PALETTED_CK));
4950
4951 for (y = 0; y < height; y++)
4952 {
4953 source = src + pitch * y;
4954 dest = dst + outpitch * y;
4955 /* This is an 1 bpp format, using the width here is fine */
4956 for (x = 0; x < width; x++) {
4957 BYTE color = *source++;
4958 *dest++ = table[color][0];
4959 *dest++ = table[color][1];
4960 *dest++ = table[color][2];
4961 *dest++ = table[color][3];
4962 }
4963 }
4964 }
4965 break;
4966
4967 case WINED3D_CT_CK_565:
4968 {
4969 /* Converting the 565 format in 5551 packed to emulate color-keying.
4970
4971 Note : in all these conversion, it would be best to average the averaging
4972 pixels to get the color of the pixel that will be color-keyed to
4973 prevent 'color bleeding'. This will be done later on if ever it is
4974 too visible.
4975
4976 Note2: Nvidia documents say that their driver does not support alpha + color keying
4977 on the same surface and disables color keying in such a case
4978 */
4979 unsigned int x, y;
4980 const WORD *Source;
4981 WORD *Dest;
4982
4983 TRACE("Color keyed 565\n");
4984
4985 for (y = 0; y < height; y++) {
4986 Source = (const WORD *)(src + y * pitch);
4987 Dest = (WORD *) (dst + y * outpitch);
4988 for (x = 0; x < width; x++ ) {
4989 WORD color = *Source++;
4990 *Dest = ((color & 0xffc0) | ((color & 0x1f) << 1));
4991 if (!color_in_range(&surface->src_blt_color_key, color))
4992 *Dest |= 0x0001;
4993 Dest++;
4994 }
4995 }
4996 }
4997 break;
4998
4999 case WINED3D_CT_CK_5551:
5000 {
5001 /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
5002 unsigned int x, y;
5003 const WORD *Source;
5004 WORD *Dest;
5005 TRACE("Color keyed 5551\n");
5006 for (y = 0; y < height; y++) {
5007 Source = (const WORD *)(src + y * pitch);
5008 Dest = (WORD *) (dst + y * outpitch);
5009 for (x = 0; x < width; x++ ) {
5010 WORD color = *Source++;
5011 *Dest = color;
5012 if (!color_in_range(&surface->src_blt_color_key, color))
5013 *Dest |= (1 << 15);
5014 else
5015 *Dest &= ~(1 << 15);
5016 Dest++;
5017 }
5018 }
5019 }
5020 break;
5021
5022 case WINED3D_CT_CK_RGB24:
5023 {
5024 /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
5025 unsigned int x, y;
5026 for (y = 0; y < height; y++)
5027 {
5028 source = src + pitch * y;
5029 dest = dst + outpitch * y;
5030 for (x = 0; x < width; x++) {
5031 DWORD color = ((DWORD)source[0] << 16) + ((DWORD)source[1] << 8) + (DWORD)source[2] ;
5032 DWORD dstcolor = color << 8;
5033 if (!color_in_range(&surface->src_blt_color_key, color))
5034 dstcolor |= 0xff;
5035 *(DWORD*)dest = dstcolor;
5036 source += 3;
5037 dest += 4;
5038 }
5039 }
5040 }
5041 break;
5042
5043 case WINED3D_CT_RGB32_888:
5044 {
5045 /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
5046 unsigned int x, y;
5047 for (y = 0; y < height; y++)
5048 {
5049 source = src + pitch * y;
5050 dest = dst + outpitch * y;
5051 for (x = 0; x < width; x++) {
5052 DWORD color = 0xffffff & *(const DWORD*)source;
5053 DWORD dstcolor = color << 8;
5054 if (!color_in_range(&surface->src_blt_color_key, color))
5055 dstcolor |= 0xff;
5056 *(DWORD*)dest = dstcolor;
5057 source += 4;
5058 dest += 4;
5059 }
5060 }
5061 }
5062 break;
5063
5064 case WINED3D_CT_CK_ARGB32:
5065 {
5066 unsigned int x, y;
5067 for (y = 0; y < height; ++y)
5068 {
5069 source = src + pitch * y;
5070 dest = dst + outpitch * y;
5071 for (x = 0; x < width; ++x)
5072 {
5073 DWORD color = *(const DWORD *)source;
5074 if (color_in_range(&surface->src_blt_color_key, color))
5075 color &= ~0xff000000;
5076 *(DWORD*)dest = color;
5077 source += 4;
5078 dest += 4;
5079 }
5080 }
5081 }
5082 break;
5083
5084 default:
5085 ERR("Unsupported conversion type %#x.\n", conversion_type);
5086 }
5087 return WINED3D_OK;
5088}
5089
5090void flip_surface(struct wined3d_surface *front, struct wined3d_surface *back)
5091{
5092 /* Flip the surface contents */
5093 /* Flip the DC */
5094 {
5095 HDC tmp;
5096 tmp = front->hDC;
5097 front->hDC = back->hDC;
5098 back->hDC = tmp;
5099 }
5100
5101 /* Flip the DIBsection */
5102 {
5103 HBITMAP tmp = front->dib.DIBsection;
5104 front->dib.DIBsection = back->dib.DIBsection;
5105 back->dib.DIBsection = tmp;
5106 }
5107
5108 /* Flip the surface data */
5109 {
5110 void* tmp;
5111
5112 tmp = front->dib.bitmap_data;
5113 front->dib.bitmap_data = back->dib.bitmap_data;
5114 back->dib.bitmap_data = tmp;
5115
5116 tmp = front->resource.allocatedMemory;
5117 front->resource.allocatedMemory = back->resource.allocatedMemory;
5118 back->resource.allocatedMemory = tmp;
5119
5120 tmp = front->resource.heapMemory;
5121 front->resource.heapMemory = back->resource.heapMemory;
5122 back->resource.heapMemory = tmp;
5123 }
5124
5125 /* Flip the PBO */
5126 {
5127 GLuint tmp_pbo = front->pbo;
5128 front->pbo = back->pbo;
5129 back->pbo = tmp_pbo;
5130 }
5131
5132 /* Flip the opengl texture */
5133 {
5134 GLuint tmp;
5135
5136 tmp = back->texture_name;
5137 back->texture_name = front->texture_name;
5138 front->texture_name = tmp;
5139
5140 tmp = back->texture_name_srgb;
5141 back->texture_name_srgb = front->texture_name_srgb;
5142 front->texture_name_srgb = tmp;
5143
5144 tmp = back->rb_multisample;
5145 back->rb_multisample = front->rb_multisample;
5146 front->rb_multisample = tmp;
5147
5148 tmp = back->rb_resolved;
5149 back->rb_resolved = front->rb_resolved;
5150 front->rb_resolved = tmp;
5151
5152 resource_unload(&back->resource);
5153 resource_unload(&front->resource);
5154 }
5155
5156 {
5157 DWORD tmp_flags = back->flags;
5158 back->flags = front->flags;
5159 front->flags = tmp_flags;
5160 }
5161}
5162
5163/* Does a direct frame buffer -> texture copy. Stretching is done with single
5164 * pixel copy calls. */
5165static void fb_copy_to_texture_direct(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
5166 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
5167{
5168 struct wined3d_device *device = dst_surface->resource.device;
5169 const struct wined3d_gl_info *gl_info;
5170 float xrel, yrel;
5171 struct wined3d_context *context;
5172 BOOL upsidedown = FALSE;
5173 RECT dst_rect = *dst_rect_in;
5174 GLenum dst_target;
5175
5176 if (dst_surface->container)
5177 dst_target = dst_surface->container->target;
5178 else
5179 dst_target = dst_surface->texture_target;
5180
5181 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
5182 * glCopyTexSubImage is a bit picky about the parameters we pass to it
5183 */
5184 if(dst_rect.top > dst_rect.bottom) {
5185 UINT tmp = dst_rect.bottom;
5186 dst_rect.bottom = dst_rect.top;
5187 dst_rect.top = tmp;
5188 upsidedown = TRUE;
5189 }
5190
5191 context = context_acquire(device, src_surface);
5192 gl_info = context->gl_info;
5193 context_apply_blit_state(context, device);
5194 surface_internal_preload(dst_surface, SRGB_RGB);
5195
5196 /* Bind the target texture */
5197 context_bind_texture(context, dst_target, dst_surface->texture_name);
5198 if (surface_is_offscreen(src_surface))
5199 {
5200 TRACE("Reading from an offscreen target\n");
5201 upsidedown = !upsidedown;
5202 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
5203 }
5204 else
5205 {
5206 gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(src_surface));
5207 }
5208 checkGLcall("glReadBuffer");
5209
5210 xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
5211 yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
5212
5213 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
5214 {
5215 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
5216
5217 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
5218 ERR("Texture filtering not supported in direct blit.\n");
5219 }
5220 else if ((filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
5221 && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
5222 {
5223 ERR("Texture filtering not supported in direct blit\n");
5224 }
5225
5226 if (upsidedown
5227 && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
5228 && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
5229 {
5230 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
5231 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
5232 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
5233 src_rect->left, src_surface->resource.height - src_rect->bottom,
5234 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
5235 }
5236 else
5237 {
5238 LONG row;
5239 UINT yoffset = src_surface->resource.height - src_rect->top + dst_rect.top - 1;
5240 /* I have to process this row by row to swap the image,
5241 * otherwise it would be upside down, so stretching in y direction
5242 * doesn't cost extra time
5243 *
5244 * However, stretching in x direction can be avoided if not necessary
5245 */
5246 for(row = dst_rect.top; row < dst_rect.bottom; row++) {
5247 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
5248 {
5249 /* Well, that stuff works, but it's very slow.
5250 * find a better way instead
5251 */
5252 LONG col;
5253
5254 for (col = dst_rect.left; col < dst_rect.right; ++col)
5255 {
5256 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
5257 dst_rect.left + col /* x offset */, row /* y offset */,
5258 src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
5259 }
5260 }
5261 else
5262 {
5263 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
5264 dst_rect.left /* x offset */, row /* y offset */,
5265 src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
5266 }
5267 }
5268 }
5269 checkGLcall("glCopyTexSubImage2D");
5270
5271 context_release(context);
5272
5273 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
5274 * path is never entered
5275 */
5276 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
5277}
5278
5279/* Uses the hardware to stretch and flip the image */
5280static void fb_copy_to_texture_hwstretch(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
5281 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
5282{
5283 struct wined3d_device *device = dst_surface->resource.device;
5284 GLuint src, backup = 0;
5285 float left, right, top, bottom; /* Texture coordinates */
5286 UINT fbwidth = src_surface->resource.width;
5287 UINT fbheight = src_surface->resource.height;
5288 const struct wined3d_gl_info *gl_info;
5289 struct wined3d_context *context;
5290 GLenum drawBuffer = GL_BACK;
5291 GLenum texture_target;
5292 BOOL noBackBufferBackup;
5293 BOOL src_offscreen;
5294 BOOL upsidedown = FALSE;
5295 RECT dst_rect = *dst_rect_in;
5296
5297 TRACE("Using hwstretch blit\n");
5298 /* Activate the Proper context for reading from the source surface, set it up for blitting */
5299 context = context_acquire(device, src_surface);
5300 gl_info = context->gl_info;
5301 context_apply_blit_state(context, device);
5302 surface_internal_preload(dst_surface, SRGB_RGB);
5303
5304 src_offscreen = surface_is_offscreen(src_surface);
5305 noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
5306 if (!noBackBufferBackup && !src_surface->texture_name)
5307 {
5308 /* Get it a description */
5309 surface_internal_preload(src_surface, SRGB_RGB);
5310 }
5311
5312 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
5313 * This way we don't have to wait for the 2nd readback to finish to leave this function.
5314 */
5315 if (context->aux_buffers >= 2)
5316 {
5317 /* Got more than one aux buffer? Use the 2nd aux buffer */
5318 drawBuffer = GL_AUX1;
5319 }
5320 else if ((!src_offscreen || device->offscreenBuffer == GL_BACK) && context->aux_buffers >= 1)
5321 {
5322 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
5323 drawBuffer = GL_AUX0;
5324 }
5325
5326 if (noBackBufferBackup)
5327 {
5328 gl_info->gl_ops.gl.p_glGenTextures(1, &backup);
5329 checkGLcall("glGenTextures");
5330 context_bind_texture(context, GL_TEXTURE_2D, backup);
5331 texture_target = GL_TEXTURE_2D;
5332 }
5333 else
5334 {
5335 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
5336 * we are reading from the back buffer, the backup can be used as source texture
5337 */
5338 texture_target = src_surface->texture_target;
5339 context_bind_texture(context, texture_target, src_surface->texture_name);
5340 gl_info->gl_ops.gl.p_glEnable(texture_target);
5341 checkGLcall("glEnable(texture_target)");
5342
5343 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
5344 src_surface->flags &= ~SFLAG_INTEXTURE;
5345 }
5346
5347 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
5348 * glCopyTexSubImage is a bit picky about the parameters we pass to it
5349 */
5350 if(dst_rect.top > dst_rect.bottom) {
5351 UINT tmp = dst_rect.bottom;
5352 dst_rect.bottom = dst_rect.top;
5353 dst_rect.top = tmp;
5354 upsidedown = TRUE;
5355 }
5356
5357 if (src_offscreen)
5358 {
5359 TRACE("Reading from an offscreen target\n");
5360 upsidedown = !upsidedown;
5361 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
5362 }
5363 else
5364 {
5365 gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(src_surface));
5366 }
5367
5368 /* TODO: Only back up the part that will be overwritten */
5369 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target, 0, 0, 0, 0, 0, fbwidth, fbheight);
5370
5371 checkGLcall("glCopyTexSubImage2D");
5372
5373 /* No issue with overriding these - the sampler is dirty due to blit usage */
5374 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER,
5375 wined3d_gl_mag_filter(magLookup, filter));
5376 checkGLcall("glTexParameteri");
5377 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
5378 wined3d_gl_min_mip_filter(minMipLookup, filter, WINED3D_TEXF_NONE));
5379 checkGLcall("glTexParameteri");
5380
5381 if (!src_surface->swapchain || src_surface == src_surface->swapchain->back_buffers[0])
5382 {
5383 src = backup ? backup : src_surface->texture_name;
5384 }
5385 else
5386 {
5387 gl_info->gl_ops.gl.p_glReadBuffer(GL_FRONT);
5388 checkGLcall("glReadBuffer(GL_FRONT)");
5389
5390 gl_info->gl_ops.gl.p_glGenTextures(1, &src);
5391 checkGLcall("glGenTextures(1, &src)");
5392 context_bind_texture(context, GL_TEXTURE_2D, src);
5393
5394 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
5395 * out for power of 2 sizes
5396 */
5397 gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_surface->pow2Width,
5398 src_surface->pow2Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
5399 checkGLcall("glTexImage2D");
5400 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, fbwidth, fbheight);
5401
5402 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5403 checkGLcall("glTexParameteri");
5404 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5405 checkGLcall("glTexParameteri");
5406
5407 gl_info->gl_ops.gl.p_glReadBuffer(GL_BACK);
5408 checkGLcall("glReadBuffer(GL_BACK)");
5409
5410 if (texture_target != GL_TEXTURE_2D)
5411 {
5412 gl_info->gl_ops.gl.p_glDisable(texture_target);
5413 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
5414 texture_target = GL_TEXTURE_2D;
5415 }
5416 }
5417 checkGLcall("glEnd and previous");
5418
5419 left = src_rect->left;
5420 right = src_rect->right;
5421
5422 if (!upsidedown)
5423 {
5424 top = src_surface->resource.height - src_rect->top;
5425 bottom = src_surface->resource.height - src_rect->bottom;
5426 }
5427 else
5428 {
5429 top = src_surface->resource.height - src_rect->bottom;
5430 bottom = src_surface->resource.height - src_rect->top;
5431 }
5432
5433 if (src_surface->flags & SFLAG_NORMCOORD)
5434 {
5435 left /= src_surface->pow2Width;
5436 right /= src_surface->pow2Width;
5437 top /= src_surface->pow2Height;
5438 bottom /= src_surface->pow2Height;
5439 }
5440
5441 /* draw the source texture stretched and upside down. The correct surface is bound already */
5442 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
5443 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
5444
5445 context_set_draw_buffer(context, drawBuffer);
5446 gl_info->gl_ops.gl.p_glReadBuffer(drawBuffer);
5447
5448 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
5449 /* bottom left */
5450 gl_info->gl_ops.gl.p_glTexCoord2f(left, bottom);
5451 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
5452
5453 /* top left */
5454 gl_info->gl_ops.gl.p_glTexCoord2f(left, top);
5455 gl_info->gl_ops.gl.p_glVertex2i(0, dst_rect.bottom - dst_rect.top);
5456
5457 /* top right */
5458 gl_info->gl_ops.gl.p_glTexCoord2f(right, top);
5459 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
5460
5461 /* bottom right */
5462 gl_info->gl_ops.gl.p_glTexCoord2f(right, bottom);
5463 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, 0);
5464 gl_info->gl_ops.gl.p_glEnd();
5465 checkGLcall("glEnd and previous");
5466
5467 if (texture_target != dst_surface->texture_target)
5468 {
5469 gl_info->gl_ops.gl.p_glDisable(texture_target);
5470 gl_info->gl_ops.gl.p_glEnable(dst_surface->texture_target);
5471 texture_target = dst_surface->texture_target;
5472 }
5473
5474 /* Now read the stretched and upside down image into the destination texture */
5475 context_bind_texture(context, texture_target, dst_surface->texture_name);
5476 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target,
5477 0,
5478 dst_rect.left, dst_rect.top, /* xoffset, yoffset */
5479 0, 0, /* We blitted the image to the origin */
5480 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
5481 checkGLcall("glCopyTexSubImage2D");
5482
5483 if (drawBuffer == GL_BACK)
5484 {
5485 /* Write the back buffer backup back. */
5486 if (backup)
5487 {
5488 if (texture_target != GL_TEXTURE_2D)
5489 {
5490 gl_info->gl_ops.gl.p_glDisable(texture_target);
5491 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
5492 texture_target = GL_TEXTURE_2D;
5493 }
5494 context_bind_texture(context, GL_TEXTURE_2D, backup);
5495 }
5496 else
5497 {
5498 if (texture_target != src_surface->texture_target)
5499 {
5500 gl_info->gl_ops.gl.p_glDisable(texture_target);
5501 gl_info->gl_ops.gl.p_glEnable(src_surface->texture_target);
5502 texture_target = src_surface->texture_target;
5503 }
5504 context_bind_texture(context, src_surface->texture_target, src_surface->texture_name);
5505 }
5506
5507 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
5508 /* top left */
5509 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, 0.0f);
5510 gl_info->gl_ops.gl.p_glVertex2i(0, fbheight);
5511
5512 /* bottom left */
5513 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, (float)fbheight / (float)src_surface->pow2Height);
5514 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
5515
5516 /* bottom right */
5517 gl_info->gl_ops.gl.p_glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width,
5518 (float)fbheight / (float)src_surface->pow2Height);
5519 gl_info->gl_ops.gl.p_glVertex2i(fbwidth, 0);
5520
5521 /* top right */
5522 gl_info->gl_ops.gl.p_glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width, 0.0f);
5523 gl_info->gl_ops.gl.p_glVertex2i(fbwidth, fbheight);
5524 gl_info->gl_ops.gl.p_glEnd();
5525 }
5526 gl_info->gl_ops.gl.p_glDisable(texture_target);
5527 checkGLcall("glDisable(texture_target)");
5528
5529 /* Cleanup */
5530 if (src != src_surface->texture_name && src != backup)
5531 {
5532 gl_info->gl_ops.gl.p_glDeleteTextures(1, &src);
5533 checkGLcall("glDeleteTextures(1, &src)");
5534 }
5535 if (backup)
5536 {
5537 gl_info->gl_ops.gl.p_glDeleteTextures(1, &backup);
5538 checkGLcall("glDeleteTextures(1, &backup)");
5539 }
5540
5541 if (wined3d_settings.strict_draw_ordering)
5542 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
5543
5544 context_release(context);
5545
5546 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
5547 * path is never entered
5548 */
5549 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
5550}
5551
5552/* Front buffer coordinates are always full screen coordinates, but our GL
5553 * drawable is limited to the window's client area. The sysmem and texture
5554 * copies do have the full screen size. Note that GL has a bottom-left
5555 * origin, while D3D has a top-left origin. */
5556void surface_translate_drawable_coords(const struct wined3d_surface *surface, HWND window, RECT *rect)
5557{
5558 UINT drawable_height;
5559 if (surface->swapchain && surface == surface->swapchain->front_buffer)
5560 {
5561#ifndef VBOX_WITH_WINE_FIXES
5562 POINT offset = {0, 0};
5563 RECT windowsize;
5564
5565 ScreenToClient(window, &offset);
5566 OffsetRect(rect, offset.x, offset.y);
5567
5568 GetClientRect(window, &windowsize);
5569 drawable_height = windowsize.bottom - windowsize.top;
5570#else
5571# ifdef VBOX_WINE_STRICT
5572 ERR("should not be here!");
5573# else
5574 WARN("should not be here!");
5575# endif
5576 drawable_height = surface->resource.height;
5577#endif
5578 }
5579 else
5580 {
5581 drawable_height = surface->resource.height;
5582 }
5583
5584 rect->top = drawable_height - rect->top;
5585 rect->bottom = drawable_height - rect->bottom;
5586}
5587
5588static void surface_blt_to_drawable(const struct wined3d_device *device,
5589 enum wined3d_texture_filter_type filter, BOOL color_key,
5590 struct wined3d_surface *src_surface, const RECT *src_rect_in,
5591 struct wined3d_surface *dst_surface, const RECT *dst_rect_in)
5592{
5593 const struct wined3d_gl_info *gl_info;
5594 struct wined3d_context *context;
5595 RECT src_rect, dst_rect;
5596
5597 src_rect = *src_rect_in;
5598 dst_rect = *dst_rect_in;
5599
5600 /* Make sure the surface is up-to-date. This should probably use
5601 * surface_load_location() and worry about the destination surface too,
5602 * unless we're overwriting it completely. */
5603 surface_internal_preload(src_surface, SRGB_RGB);
5604
5605 /* Activate the destination context, set it up for blitting */
5606 context = context_acquire(device, dst_surface);
5607 gl_info = context->gl_info;
5608 context_apply_blit_state(context, device);
5609
5610 if (!surface_is_offscreen(dst_surface))
5611#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
5612 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
5613#else
5614 surface_translate_drawable_coords(dst_surface, context->swapchain->win_handle, &dst_rect);
5615#endif
5616
5617 device->blitter->set_shader(device->blit_priv, context, src_surface);
5618
5619 if (color_key)
5620 {
5621 gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST);
5622 checkGLcall("glEnable(GL_ALPHA_TEST)");
5623
5624 /* When the primary render target uses P8, the alpha component
5625 * contains the palette index. Which means that the colorkey is one of
5626 * the palette entries. In other cases pixels that should be masked
5627 * away have alpha set to 0. */
5628 if (primary_render_target_is_p8(device))
5629 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL,
5630 (float)src_surface->src_blt_color_key.color_space_low_value / 256.0f);
5631 else
5632 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL, 0.0f);
5633 checkGLcall("glAlphaFunc");
5634 }
5635 else
5636 {
5637 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
5638 checkGLcall("glDisable(GL_ALPHA_TEST)");
5639 }
5640
5641 draw_textured_quad(src_surface, context, &src_rect, &dst_rect, filter);
5642
5643 if (color_key)
5644 {
5645 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
5646 checkGLcall("glDisable(GL_ALPHA_TEST)");
5647 }
5648
5649 /* Leave the opengl state valid for blitting */
5650 device->blitter->unset_shader(context->gl_info);
5651
5652 if (wined3d_settings.strict_draw_ordering
5653 || (dst_surface->swapchain && dst_surface->swapchain->front_buffer == dst_surface))
5654 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
5655
5656 context_release(context);
5657}
5658
5659/* Do not call while under the GL lock. */
5660HRESULT surface_color_fill(struct wined3d_surface *s, const RECT *rect, const struct wined3d_color *color)
5661{
5662 struct wined3d_device *device = s->resource.device;
5663 const struct blit_shader *blitter;
5664
5665 blitter = wined3d_select_blitter(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_FILL,
5666 NULL, 0, 0, NULL, rect, s->resource.usage, s->resource.pool, s->resource.format);
5667 if (!blitter)
5668 {
5669 FIXME("No blitter is capable of performing the requested color fill operation.\n");
5670 return WINED3DERR_INVALIDCALL;
5671 }
5672
5673 return blitter->color_fill(device, s, rect, color);
5674}
5675
5676/* Do not call while under the GL lock. */
5677static HRESULT IWineD3DSurfaceImpl_BltOverride(struct wined3d_surface *dst_surface, const RECT *dst_rect,
5678 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags, const WINEDDBLTFX *DDBltFx,
5679 enum wined3d_texture_filter_type filter)
5680{
5681 struct wined3d_device *device = dst_surface->resource.device;
5682 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
5683 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
5684
5685 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
5686 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
5687 flags, DDBltFx, debug_d3dtexturefiltertype(filter));
5688
5689 /* Get the swapchain. One of the surfaces has to be a primary surface */
5690 if (dst_surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
5691 {
5692 WARN("Destination is in sysmem, rejecting gl blt\n");
5693 return WINED3DERR_INVALIDCALL;
5694 }
5695
5696 dst_swapchain = dst_surface->swapchain;
5697
5698 if (src_surface)
5699 {
5700 if (src_surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
5701 {
5702 WARN("Src is in sysmem, rejecting gl blt\n");
5703 return WINED3DERR_INVALIDCALL;
5704 }
5705
5706 src_swapchain = src_surface->swapchain;
5707 }
5708 else
5709 {
5710 src_swapchain = NULL;
5711 }
5712
5713 /* Early sort out of cases where no render target is used */
5714 if (!dst_swapchain && !src_swapchain
5715 && src_surface != device->fb.render_targets[0]
5716 && dst_surface != device->fb.render_targets[0])
5717 {
5718 TRACE("No surface is render target, not using hardware blit.\n");
5719 return WINED3DERR_INVALIDCALL;
5720 }
5721
5722 /* No destination color keying supported */
5723 if (flags & (WINEDDBLT_KEYDEST | WINEDDBLT_KEYDESTOVERRIDE))
5724 {
5725 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
5726 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
5727 return WINED3DERR_INVALIDCALL;
5728 }
5729
5730 if (dst_swapchain && dst_swapchain == src_swapchain)
5731 {
5732 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
5733 return WINED3DERR_INVALIDCALL;
5734 }
5735
5736 if (dst_swapchain && src_swapchain)
5737 {
5738 FIXME("Implement hardware blit between two different swapchains\n");
5739 return WINED3DERR_INVALIDCALL;
5740 }
5741
5742 if (dst_swapchain)
5743 {
5744 /* Handled with regular texture -> swapchain blit */
5745 if (src_surface == device->fb.render_targets[0])
5746 TRACE("Blit from active render target to a swapchain\n");
5747 }
5748 else if (src_swapchain && dst_surface == device->fb.render_targets[0])
5749 {
5750 FIXME("Implement blit from a swapchain to the active render target\n");
5751 return WINED3DERR_INVALIDCALL;
5752 }
5753
5754 if ((src_swapchain || src_surface == device->fb.render_targets[0]) && !dst_swapchain)
5755 {
5756 /* Blit from render target to texture */
5757 BOOL stretchx;
5758
5759 /* P8 read back is not implemented */
5760 if (src_surface->resource.format->id == WINED3DFMT_P8_UINT
5761 || dst_surface->resource.format->id == WINED3DFMT_P8_UINT)
5762 {
5763 TRACE("P8 read back not supported by frame buffer to texture blit\n");
5764 return WINED3DERR_INVALIDCALL;
5765 }
5766
5767 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
5768 {
5769 TRACE("Color keying not supported by frame buffer to texture blit\n");
5770 return WINED3DERR_INVALIDCALL;
5771 /* Destination color key is checked above */
5772 }
5773
5774 if (dst_rect->right - dst_rect->left != src_rect->right - src_rect->left)
5775 stretchx = TRUE;
5776 else
5777 stretchx = FALSE;
5778
5779 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
5780 * flip the image nor scale it.
5781 *
5782 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
5783 * -> If the app wants a image width an unscaled width, copy it line per line
5784 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
5785 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
5786 * back buffer. This is slower than reading line per line, thus not used for flipping
5787 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
5788 * pixel by pixel. */
5789 if (!stretchx || dst_rect->right - dst_rect->left > src_surface->resource.width
5790 || dst_rect->bottom - dst_rect->top > src_surface->resource.height)
5791 {
5792 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
5793 fb_copy_to_texture_direct(dst_surface, src_surface, src_rect, dst_rect, filter);
5794 }
5795 else
5796 {
5797 TRACE("Using hardware stretching to flip / stretch the texture.\n");
5798 fb_copy_to_texture_hwstretch(dst_surface, src_surface, src_rect, dst_rect, filter);
5799 }
5800
5801 if (!dst_surface->resource.map_count && !(dst_surface->flags & SFLAG_DONOTFREE))
5802 {
5803 HeapFree(GetProcessHeap(), 0, dst_surface->resource.heapMemory);
5804 dst_surface->resource.allocatedMemory = NULL;
5805 dst_surface->resource.heapMemory = NULL;
5806 }
5807 else
5808 {
5809 dst_surface->flags &= ~SFLAG_INSYSMEM;
5810 }
5811
5812 return WINED3D_OK;
5813 }
5814 else if (src_surface)
5815 {
5816 /* Blit from offscreen surface to render target */
5817 struct wined3d_color_key old_blt_key = src_surface->src_blt_color_key;
5818 DWORD oldCKeyFlags = src_surface->CKeyFlags;
5819
5820 TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface);
5821
5822 if (!device->blitter->blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
5823 src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
5824 dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
5825 {
5826 FIXME("Unsupported blit operation falling back to software\n");
5827 return WINED3DERR_INVALIDCALL;
5828 }
5829
5830 /* Color keying: Check if we have to do a color keyed blt,
5831 * and if not check if a color key is activated.
5832 *
5833 * Just modify the color keying parameters in the surface and restore them afterwards
5834 * The surface keeps track of the color key last used to load the opengl surface.
5835 * PreLoad will catch the change to the flags and color key and reload if necessary.
5836 */
5837 if (flags & WINEDDBLT_KEYSRC)
5838 {
5839 /* Use color key from surface */
5840 }
5841 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
5842 {
5843 /* Use color key from DDBltFx */
5844 src_surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
5845 src_surface->src_blt_color_key = DDBltFx->ddckSrcColorkey;
5846 }
5847 else
5848 {
5849 /* Do not use color key */
5850 src_surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
5851 }
5852
5853 surface_blt_to_drawable(device, filter, flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE),
5854 src_surface, src_rect, dst_surface, dst_rect);
5855
5856 /* Restore the color key parameters */
5857 src_surface->CKeyFlags = oldCKeyFlags;
5858 src_surface->src_blt_color_key = old_blt_key;
5859
5860 surface_modify_location(dst_surface, dst_surface->draw_binding, TRUE);
5861
5862 return WINED3D_OK;
5863 }
5864
5865 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
5866 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
5867 return WINED3DERR_INVALIDCALL;
5868}
5869
5870/* Context activation is done by the caller. */
5871static void surface_depth_blt(const struct wined3d_surface *surface, struct wined3d_context *context,
5872 GLuint texture, GLint x, GLint y, GLsizei w, GLsizei h, GLenum target)
5873{
5874 struct wined3d_device *device = surface->resource.device;
5875 const struct wined3d_gl_info *gl_info = context->gl_info;
5876 GLint compare_mode = GL_NONE;
5877 struct blt_info info;
5878 GLint old_binding = 0;
5879 RECT rect;
5880
5881 gl_info->gl_ops.gl.p_glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
5882
5883 gl_info->gl_ops.gl.p_glDisable(GL_CULL_FACE);
5884 gl_info->gl_ops.gl.p_glDisable(GL_BLEND);
5885 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
5886 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
5887 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST);
5888 gl_info->gl_ops.gl.p_glEnable(GL_DEPTH_TEST);
5889 gl_info->gl_ops.gl.p_glDepthFunc(GL_ALWAYS);
5890 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
5891 gl_info->gl_ops.gl.p_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
5892 gl_info->gl_ops.gl.p_glViewport(x, y, w, h);
5893 gl_info->gl_ops.gl.p_glDepthRange(0.0, 1.0);
5894
5895 SetRect(&rect, 0, h, w, 0);
5896 surface_get_blt_info(target, &rect, surface->pow2Width, surface->pow2Height, &info);
5897 context_active_texture(context, context->gl_info, 0);
5898 gl_info->gl_ops.gl.p_glGetIntegerv(info.binding, &old_binding);
5899 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, texture);
5900 if (gl_info->supported[ARB_SHADOW])
5901 {
5902 gl_info->gl_ops.gl.p_glGetTexParameteriv(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, &compare_mode);
5903 if (compare_mode != GL_NONE)
5904 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
5905 }
5906
5907 device->shader_backend->shader_select_depth_blt(device->shader_priv,
5908 gl_info, info.tex_type, &surface->ds_current_size);
5909
5910 gl_info->gl_ops.gl.p_glBegin(GL_TRIANGLE_STRIP);
5911 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[0]);
5912 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, -1.0f);
5913 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[1]);
5914 gl_info->gl_ops.gl.p_glVertex2f(1.0f, -1.0f);
5915 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[2]);
5916 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, 1.0f);
5917 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[3]);
5918 gl_info->gl_ops.gl.p_glVertex2f(1.0f, 1.0f);
5919 gl_info->gl_ops.gl.p_glEnd();
5920
5921 if (compare_mode != GL_NONE)
5922 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, compare_mode);
5923 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, old_binding);
5924
5925 gl_info->gl_ops.gl.p_glPopAttrib();
5926
5927 device->shader_backend->shader_deselect_depth_blt(device->shader_priv, gl_info);
5928}
5929
5930void surface_modify_ds_location(struct wined3d_surface *surface,
5931 DWORD location, UINT w, UINT h)
5932{
5933 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface, location, w, h);
5934
5935 if (location & ~(SFLAG_LOCATIONS | SFLAG_DISCARDED))
5936 FIXME("Invalid location (%#x) specified.\n", location);
5937
5938 if (((surface->flags & SFLAG_INTEXTURE) && !(location & SFLAG_INTEXTURE))
5939 || (!(surface->flags & SFLAG_INTEXTURE) && (location & SFLAG_INTEXTURE)))
5940 {
5941 if (surface->container)
5942 {
5943 TRACE("Passing to container.\n");
5944 wined3d_texture_set_dirty(surface->container, TRUE);
5945 }
5946 }
5947
5948 surface->ds_current_size.cx = w;
5949 surface->ds_current_size.cy = h;
5950 surface->flags &= ~(SFLAG_LOCATIONS | SFLAG_DISCARDED);
5951 surface->flags |= location;
5952}
5953
5954/* Context activation is done by the caller. */
5955void surface_load_ds_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
5956{
5957 const struct wined3d_gl_info *gl_info = context->gl_info;
5958 struct wined3d_device *device = surface->resource.device;
5959 GLsizei w, h;
5960
5961 TRACE("surface %p, new location %#x.\n", surface, location);
5962
5963 /* TODO: Make this work for modes other than FBO */
5964 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
5965
5966 if (!(surface->flags & location))
5967 {
5968 w = surface->ds_current_size.cx;
5969 h = surface->ds_current_size.cy;
5970 surface->ds_current_size.cx = 0;
5971 surface->ds_current_size.cy = 0;
5972 }
5973 else
5974 {
5975 w = surface->resource.width;
5976 h = surface->resource.height;
5977 }
5978
5979 if (surface->ds_current_size.cx == surface->resource.width
5980 && surface->ds_current_size.cy == surface->resource.height)
5981 {
5982 TRACE("Location (%#x) is already up to date.\n", location);
5983 return;
5984 }
5985
5986 if (surface->current_renderbuffer)
5987 {
5988 FIXME("Not supported with fixed up depth stencil.\n");
5989 return;
5990 }
5991
5992 if (surface->flags & SFLAG_DISCARDED)
5993 {
5994 TRACE("Surface was discarded, no need copy data.\n");
5995 switch (location)
5996 {
5997 case SFLAG_INTEXTURE:
5998 surface_prepare_texture(surface, context, FALSE);
5999 break;
6000 case SFLAG_INRB_MULTISAMPLE:
6001 surface_prepare_rb(surface, gl_info, TRUE);
6002 break;
6003 case SFLAG_INDRAWABLE:
6004 /* Nothing to do */
6005 break;
6006 default:
6007 FIXME("Unhandled location %#x\n", location);
6008 }
6009 surface->flags &= ~SFLAG_DISCARDED;
6010 surface->flags |= location;
6011 surface->ds_current_size.cx = surface->resource.width;
6012 surface->ds_current_size.cy = surface->resource.height;
6013 return;
6014 }
6015
6016 if (!(surface->flags & SFLAG_LOCATIONS))
6017 {
6018 FIXME("No up to date depth stencil location.\n");
6019 surface->flags |= location;
6020 surface->ds_current_size.cx = surface->resource.width;
6021 surface->ds_current_size.cy = surface->resource.height;
6022 return;
6023 }
6024
6025 if (location == SFLAG_INTEXTURE)
6026 {
6027 GLint old_binding = 0;
6028 GLenum bind_target;
6029
6030 /* The render target is allowed to be smaller than the depth/stencil
6031 * buffer, so the onscreen depth/stencil buffer is potentially smaller
6032 * than the offscreen surface. Don't overwrite the offscreen surface
6033 * with undefined data. */
6034 w = min(w, context->swapchain->desc.backbuffer_width);
6035 h = min(h, context->swapchain->desc.backbuffer_height);
6036
6037 TRACE("Copying onscreen depth buffer to depth texture.\n");
6038
6039 if (!device->depth_blt_texture)
6040 gl_info->gl_ops.gl.p_glGenTextures(1, &device->depth_blt_texture);
6041
6042 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
6043 * directly on the FBO texture. That's because we need to flip. */
6044 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
6045 context->swapchain->front_buffer, NULL, SFLAG_INDRAWABLE);
6046 if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
6047 {
6048 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6049 bind_target = GL_TEXTURE_RECTANGLE_ARB;
6050 }
6051 else
6052 {
6053 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6054 bind_target = GL_TEXTURE_2D;
6055 }
6056 gl_info->gl_ops.gl.p_glBindTexture(bind_target, device->depth_blt_texture);
6057 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
6058 * internal format, because the internal format might include stencil
6059 * data. In principle we should copy stencil data as well, but unless
6060 * the driver supports stencil export it's hard to do, and doesn't
6061 * seem to be needed in practice. If the hardware doesn't support
6062 * writing stencil data, the glCopyTexImage2D() call might trigger
6063 * software fallbacks. */
6064 gl_info->gl_ops.gl.p_glCopyTexImage2D(bind_target, 0, GL_DEPTH_COMPONENT, 0, 0, w, h, 0);
6065 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6066 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6067 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
6068 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
6069 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
6070 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6071 gl_info->gl_ops.gl.p_glBindTexture(bind_target, old_binding);
6072
6073 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
6074 NULL, surface, SFLAG_INTEXTURE);
6075 context_set_draw_buffer(context, GL_NONE);
6076
6077 /* Do the actual blit */
6078 surface_depth_blt(surface, context, device->depth_blt_texture, 0, 0, w, h, bind_target);
6079 checkGLcall("depth_blt");
6080
6081 context_invalidate_state(context, STATE_FRAMEBUFFER);
6082
6083 if (wined3d_settings.strict_draw_ordering)
6084 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
6085 }
6086 else if (location == SFLAG_INDRAWABLE)
6087 {
6088 TRACE("Copying depth texture to onscreen depth buffer.\n");
6089
6090 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
6091 context->swapchain->front_buffer, NULL, SFLAG_INDRAWABLE);
6092 surface_depth_blt(surface, context, surface->texture_name,
6093 0, surface->pow2Height - h, w, h, surface->texture_target);
6094 checkGLcall("depth_blt");
6095
6096 context_invalidate_state(context, STATE_FRAMEBUFFER);
6097
6098 if (wined3d_settings.strict_draw_ordering)
6099 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
6100 }
6101 else
6102 {
6103 ERR("Invalid location (%#x) specified.\n", location);
6104 }
6105
6106 surface->flags |= location;
6107 surface->ds_current_size.cx = surface->resource.width;
6108 surface->ds_current_size.cy = surface->resource.height;
6109}
6110
6111void surface_modify_location(struct wined3d_surface *surface, DWORD location, BOOL persistent)
6112{
6113 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
6114 struct wined3d_surface *overlay;
6115
6116 TRACE("surface %p, location %s, persistent %#x.\n",
6117 surface, debug_surflocation(location), persistent);
6118
6119 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && surface_is_offscreen(surface)
6120 && !(surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
6121 && (location & SFLAG_INDRAWABLE))
6122 ERR("Trying to invalidate the SFLAG_INDRAWABLE location of an offscreen surface.\n");
6123
6124 if (location & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)
6125 && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6126 location |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX);
6127
6128 if (persistent)
6129 {
6130 if (((surface->flags & SFLAG_INTEXTURE) && !(location & SFLAG_INTEXTURE))
6131 || ((surface->flags & SFLAG_INSRGBTEX) && !(location & SFLAG_INSRGBTEX)))
6132 {
6133 if (surface->container)
6134 {
6135 TRACE("Passing to container.\n");
6136 wined3d_texture_set_dirty(surface->container, TRUE);
6137 }
6138 }
6139
6140#ifdef VBOX_WITH_WDDM
6141 {
6142 /* sometimes wine can call ModifyLocation(SFLAG_INTEXTURE, TRUE) for surfaces that do not yet have
6143 * ogl texture backend assigned, e.g. when doing ColorFill right after surface creation
6144 * to prevent wine state breakage that could occur later on in that case, we check
6145 * whether tex gen is needed here and generate it accordingly */
6146 if (!surface->texture_name)
6147 {
6148 Assert(!(surface->flags & SFLAG_INTEXTURE));
6149 if (location & SFLAG_INTEXTURE)
6150 {
6151 Assert(0);
6152// struct wined3d_context *context = NULL;
6153// IWineD3DDeviceImpl *device = This->resource.device;
6154// const struct wined3d_gl_info *gl_info;
6155//
6156// if (!device->isInDraw) context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6157// gl_info = context->gl_info;
6158//
6159// surface_prepare_texture(This, gl_info, FALSE);
6160//
6161// if (context) context_release(context);
6162 }
6163 }
6164
6165 if (!surface->texture_name_srgb)
6166 {
6167 Assert(!(surface->flags & SFLAG_INSRGBTEX));
6168 if (location & SFLAG_INSRGBTEX)
6169 {
6170 Assert(0);
6171// struct wined3d_context *context = NULL;
6172// IWineD3DDeviceImpl *device = This->resource.device;
6173// const struct wined3d_gl_info *gl_info;
6174//
6175// if (!device->isInDraw) context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6176// gl_info = context->gl_info;
6177//
6178// surface_prepare_texture(This, gl_info, TRUE);
6179//
6180// if (context) context_release(context);
6181 }
6182 }
6183 }
6184#endif
6185
6186 surface->flags &= ~SFLAG_LOCATIONS;
6187 surface->flags |= location;
6188
6189 /* Redraw emulated overlays, if any */
6190 if (location & SFLAG_INDRAWABLE && !list_empty(&surface->overlays))
6191 {
6192 LIST_FOR_EACH_ENTRY(overlay, &surface->overlays, struct wined3d_surface, overlay_entry)
6193 {
6194 surface_draw_overlay(overlay);
6195 }
6196 }
6197 }
6198 else
6199 {
6200 if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) && (location & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)))
6201 {
6202 if (surface->container)
6203 {
6204 TRACE("Passing to container\n");
6205 wined3d_texture_set_dirty(surface->container, TRUE);
6206 }
6207 }
6208 surface->flags &= ~location;
6209 }
6210
6211#ifdef VBOX_WITH_WDDM
6212 if(VBOXSHRC_IS_SHARED_UNLOCKED(surface)) {
6213 /* with the shared resource only texture can be considered valid
6214 * to make sure changes done to the resource in the other device context are visible
6215 * because the resource contents is shared via texture.
6216 * This is why we ensure texture location is the one and only which is always valid */
6217 if(!(surface->flags & SFLAG_INTEXTURE)) {
6218 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
6219 } else {
6220 surface->flags &= ~SFLAG_LOCATIONS;
6221 surface->flags |= SFLAG_INTEXTURE;
6222 }
6223 }
6224 else if (surface->flags & SFLAG_CLIENTMEM)
6225 {
6226 if(!(surface->flags & SFLAG_INSYSMEM)) {
6227 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
6228 } else {
6229 surface->flags &= ~SFLAG_LOCATIONS;
6230 surface->flags |= SFLAG_INSYSMEM;
6231 }
6232 }
6233#endif
6234
6235
6236 if (!(surface->flags & SFLAG_LOCATIONS))
6237 {
6238 ERR("Surface %p does not have any up to date location.\n", surface);
6239 }
6240}
6241
6242static DWORD resource_access_from_location(DWORD location)
6243{
6244 switch (location)
6245 {
6246 case SFLAG_INSYSMEM:
6247 return WINED3D_RESOURCE_ACCESS_CPU;
6248
6249 case SFLAG_INDRAWABLE:
6250 case SFLAG_INSRGBTEX:
6251 case SFLAG_INTEXTURE:
6252 case SFLAG_INRB_MULTISAMPLE:
6253 case SFLAG_INRB_RESOLVED:
6254 return WINED3D_RESOURCE_ACCESS_GPU;
6255
6256 default:
6257 FIXME("Unhandled location %#x.\n", location);
6258 return 0;
6259 }
6260}
6261
6262static void surface_load_sysmem(struct wined3d_surface *surface,
6263 const struct wined3d_gl_info *gl_info, const RECT *rect)
6264{
6265 surface_prepare_system_memory(surface);
6266
6267 if (surface->flags & (SFLAG_INRB_MULTISAMPLE | SFLAG_INRB_RESOLVED))
6268 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
6269
6270 /* Download the surface to system memory. */
6271 if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX))
6272 {
6273 struct wined3d_device *device = surface->resource.device;
6274 struct wined3d_context *context;
6275
6276 /* TODO: Use already acquired context when possible. */
6277 context = context_acquire(device, NULL);
6278
6279 surface_bind_and_dirtify(surface, context, !(surface->flags & SFLAG_INTEXTURE));
6280 surface_download_data(surface, gl_info);
6281
6282 context_release(context);
6283
6284 return;
6285 }
6286
6287 if (surface->flags & SFLAG_INDRAWABLE)
6288 {
6289 read_from_framebuffer(surface, rect, surface->resource.allocatedMemory,
6290 wined3d_surface_get_pitch(surface));
6291 return;
6292 }
6293
6294 FIXME("Can't load surface %p with location flags %#x into sysmem.\n",
6295 surface, surface->flags & SFLAG_LOCATIONS);
6296}
6297
6298static HRESULT surface_load_drawable(struct wined3d_surface *surface,
6299 const struct wined3d_gl_info *gl_info, const RECT *rect)
6300{
6301 struct wined3d_device *device = surface->resource.device;
6302 enum wined3d_conversion_type convert;
6303 struct wined3d_format format;
6304 UINT byte_count;
6305 BYTE *mem;
6306
6307 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && surface_is_offscreen(surface))
6308 {
6309 ERR("Trying to load offscreen surface into SFLAG_INDRAWABLE.\n");
6310 return WINED3DERR_INVALIDCALL;
6311 }
6312
6313 if (wined3d_settings.rendertargetlock_mode == RTL_READTEX)
6314 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
6315
6316 if (surface->flags & SFLAG_INTEXTURE)
6317 {
6318 RECT r;
6319
6320 surface_get_rect(surface, rect, &r);
6321 surface_blt_to_drawable(device, WINED3D_TEXF_POINT, FALSE, surface, &r, surface, &r);
6322
6323 return WINED3D_OK;
6324 }
6325
6326 if ((surface->flags & SFLAG_LOCATIONS) == SFLAG_INSRGBTEX)
6327 {
6328 /* This needs colorspace conversion from sRGB to RGB. We take the slow
6329 * path through sysmem. */
6330 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6331 }
6332
6333 d3dfmt_get_conv(surface, FALSE, FALSE, &format, &convert);
6334
6335 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
6336 * SFLAG_CONVERTED but it isn't set (yet) in all cases where it is getting
6337 * called. */
6338 if ((convert != WINED3D_CT_NONE) && (surface->flags & SFLAG_PBO))
6339 {
6340 struct wined3d_context *context;
6341
6342 TRACE("Removing the pbo attached to surface %p.\n", surface);
6343
6344 /* TODO: Use already acquired context when possible. */
6345 context = context_acquire(device, NULL);
6346
6347 surface_remove_pbo(surface, gl_info);
6348
6349 context_release(context);
6350 }
6351
6352 if ((convert != WINED3D_CT_NONE) && surface->resource.allocatedMemory)
6353 {
6354 UINT height = surface->resource.height;
6355 UINT width = surface->resource.width;
6356 UINT src_pitch, dst_pitch;
6357
6358 byte_count = format.conv_byte_count;
6359 src_pitch = wined3d_surface_get_pitch(surface);
6360
6361 /* Stick to the alignment for the converted surface too, makes it
6362 * easier to load the surface. */
6363 dst_pitch = width * byte_count;
6364 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6365
6366 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
6367 {
6368 ERR("Out of memory (%u).\n", dst_pitch * height);
6369 return E_OUTOFMEMORY;
6370 }
6371
6372 d3dfmt_convert_surface(surface->resource.allocatedMemory, mem,
6373 src_pitch, width, height, dst_pitch, convert, surface);
6374
6375 surface->flags |= SFLAG_CONVERTED;
6376 }
6377 else
6378 {
6379 surface->flags &= ~SFLAG_CONVERTED;
6380 mem = surface->resource.allocatedMemory;
6381 byte_count = format.byte_count;
6382 }
6383
6384 flush_to_framebuffer_drawpixels(surface, rect, format.glFormat, format.glType, byte_count, mem);
6385
6386 /* Don't delete PBO memory. */
6387 if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO))
6388 HeapFree(GetProcessHeap(), 0, mem);
6389
6390 return WINED3D_OK;
6391}
6392
6393static HRESULT surface_load_texture(struct wined3d_surface *surface,
6394 const struct wined3d_gl_info *gl_info, const RECT *rect, BOOL srgb)
6395{
6396 RECT src_rect = {0, 0, surface->resource.width, surface->resource.height};
6397 struct wined3d_device *device = surface->resource.device;
6398 enum wined3d_conversion_type convert;
6399 struct wined3d_context *context;
6400 UINT width, src_pitch, dst_pitch;
6401 struct wined3d_bo_address data;
6402 struct wined3d_format format;
6403 POINT dst_point = {0, 0};
6404 BYTE *mem;
6405
6406 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
6407 && surface_is_offscreen(surface)
6408 && (surface->flags & SFLAG_INDRAWABLE))
6409 {
6410 surface_load_fb_texture(surface, srgb);
6411
6412 return WINED3D_OK;
6413 }
6414
6415 if (surface->flags & (SFLAG_INSRGBTEX | SFLAG_INTEXTURE)
6416 && (surface->resource.format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)
6417 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
6418 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
6419 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
6420 {
6421 if (srgb)
6422 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, SFLAG_INTEXTURE,
6423 &src_rect, surface, SFLAG_INSRGBTEX, &src_rect);
6424 else
6425 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, SFLAG_INSRGBTEX,
6426 &src_rect, surface, SFLAG_INTEXTURE, &src_rect);
6427
6428 return WINED3D_OK;
6429 }
6430
6431 if (surface->flags & (SFLAG_INRB_MULTISAMPLE | SFLAG_INRB_RESOLVED)
6432 && (!srgb || (surface->resource.format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB))
6433 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
6434 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
6435 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
6436 {
6437 DWORD src_location = surface->flags & SFLAG_INRB_RESOLVED ? SFLAG_INRB_RESOLVED : SFLAG_INRB_MULTISAMPLE;
6438 DWORD dst_location = srgb ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
6439 RECT rect = {0, 0, surface->resource.width, surface->resource.height};
6440
6441 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, src_location,
6442 &rect, surface, dst_location, &rect);
6443
6444 return WINED3D_OK;
6445 }
6446
6447 /* Upload from system memory */
6448
6449 d3dfmt_get_conv(surface, TRUE /* We need color keying */,
6450 TRUE /* We will use textures */, &format, &convert);
6451
6452 if (srgb)
6453 {
6454 if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSYSMEM)) == SFLAG_INTEXTURE)
6455 {
6456 /* Performance warning... */
6457 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface);
6458 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6459 }
6460 }
6461 else
6462 {
6463 if ((surface->flags & (SFLAG_INSRGBTEX | SFLAG_INSYSMEM)) == SFLAG_INSRGBTEX)
6464 {
6465 /* Performance warning... */
6466 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface);
6467 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6468 }
6469 }
6470
6471 if (!(surface->flags & SFLAG_INSYSMEM))
6472 {
6473 WARN("Trying to load a texture from sysmem, but SFLAG_INSYSMEM is not set.\n");
6474 /* Lets hope we get it from somewhere... */
6475 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6476 }
6477
6478 /* TODO: Use already acquired context when possible. */
6479 context = context_acquire(device, NULL);
6480
6481 surface_prepare_texture(surface, context, srgb);
6482 surface_bind_and_dirtify(surface, context, srgb);
6483
6484 if (surface->CKeyFlags & WINEDDSD_CKSRCBLT)
6485 {
6486 surface->flags |= SFLAG_GLCKEY;
6487 surface->gl_color_key = surface->src_blt_color_key;
6488 }
6489 else surface->flags &= ~SFLAG_GLCKEY;
6490
6491 width = surface->resource.width;
6492 src_pitch = wined3d_surface_get_pitch(surface);
6493
6494 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
6495 * SFLAG_CONVERTED but it isn't set (yet) in all cases it is getting
6496 * called. */
6497 if ((convert != WINED3D_CT_NONE || format.convert) && (surface->flags & SFLAG_PBO))
6498 {
6499 TRACE("Removing the pbo attached to surface %p.\n", surface);
6500 surface_remove_pbo(surface, gl_info);
6501 }
6502
6503 if (format.convert)
6504 {
6505 /* This code is entered for texture formats which need a fixup. */
6506 UINT height = surface->resource.height;
6507
6508 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6509 dst_pitch = width * format.conv_byte_count;
6510 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6511
6512 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
6513 {
6514 ERR("Out of memory (%u).\n", dst_pitch * height);
6515 context_release(context);
6516 return E_OUTOFMEMORY;
6517 }
6518 format.convert(surface->resource.allocatedMemory, mem, src_pitch, width, height);
6519 format.byte_count = format.conv_byte_count;
6520 src_pitch = dst_pitch;
6521 }
6522 else if (convert != WINED3D_CT_NONE && surface->resource.allocatedMemory)
6523 {
6524 /* This code is only entered for color keying fixups */
6525 UINT height = surface->resource.height;
6526
6527 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6528 dst_pitch = width * format.conv_byte_count;
6529 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6530
6531 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
6532 {
6533 ERR("Out of memory (%u).\n", dst_pitch * height);
6534 context_release(context);
6535 return E_OUTOFMEMORY;
6536 }
6537 d3dfmt_convert_surface(surface->resource.allocatedMemory, mem, src_pitch,
6538 width, height, dst_pitch, convert, surface);
6539 format.byte_count = format.conv_byte_count;
6540 src_pitch = dst_pitch;
6541 }
6542 else
6543 {
6544 mem = surface->resource.allocatedMemory;
6545 }
6546
6547 data.buffer_object = surface->pbo;
6548 data.addr = mem;
6549 surface_upload_data(surface, gl_info, &format, &src_rect, src_pitch, &dst_point, srgb, &data);
6550
6551 context_release(context);
6552
6553 /* Don't delete PBO memory. */
6554 if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO))
6555 HeapFree(GetProcessHeap(), 0, mem);
6556
6557 return WINED3D_OK;
6558}
6559
6560static void surface_multisample_resolve(struct wined3d_surface *surface)
6561{
6562 RECT rect = {0, 0, surface->resource.width, surface->resource.height};
6563
6564 if (!(surface->flags & SFLAG_INRB_MULTISAMPLE))
6565 ERR("Trying to resolve multisampled surface %p, but location SFLAG_INRB_MULTISAMPLE not current.\n", surface);
6566
6567 surface_blt_fbo(surface->resource.device, WINED3D_TEXF_POINT,
6568 surface, SFLAG_INRB_MULTISAMPLE, &rect, surface, SFLAG_INRB_RESOLVED, &rect);
6569}
6570
6571HRESULT surface_load_location(struct wined3d_surface *surface, DWORD location, const RECT *rect)
6572{
6573 struct wined3d_device *device = surface->resource.device;
6574 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6575 HRESULT hr;
6576
6577 TRACE("surface %p, location %s, rect %s.\n", surface, debug_surflocation(location), wine_dbgstr_rect(rect));
6578
6579 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
6580 {
6581 if (location == SFLAG_INTEXTURE && surface->flags & SFLAG_INDRAWABLE)
6582 {
6583 struct wined3d_context *context = context_acquire(device, NULL);
6584 surface_load_ds_location(surface, context, location);
6585 context_release(context);
6586#ifndef VBOX_WITH_WDDM
6587 return WINED3D_OK;
6588#else
6589 goto post_process;
6590#endif
6591 }
6592 else if (location & surface->flags && surface->draw_binding != SFLAG_INDRAWABLE)
6593 {
6594 /* Already up to date, nothing to do. */
6595#ifndef VBOX_WITH_WDDM
6596 return WINED3D_OK;
6597#else
6598 goto post_process;
6599#endif
6600 }
6601 else
6602 {
6603 FIXME("Unimplemented copy from %s to %s for depth/stencil buffers.\n",
6604 debug_surflocation(surface->flags & SFLAG_LOCATIONS), debug_surflocation(location));
6605 return WINED3DERR_INVALIDCALL;
6606 }
6607 }
6608
6609 if (location == SFLAG_INSRGBTEX && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6610 location = SFLAG_INTEXTURE;
6611
6612 if (surface->flags & location)
6613 {
6614 TRACE("Location already up to date.\n");
6615
6616 if (location == SFLAG_INSYSMEM && !(surface->flags & SFLAG_PBO)
6617 && surface_need_pbo(surface, gl_info))
6618 surface_load_pbo(surface, gl_info);
6619
6620#ifndef VBOX_WITH_WDDM
6621 return WINED3D_OK;
6622#else
6623 goto post_process;
6624#endif
6625 }
6626
6627 if (WARN_ON(d3d_surface))
6628 {
6629 DWORD required_access = resource_access_from_location(location);
6630 if ((surface->resource.access_flags & required_access) != required_access)
6631 WARN("Operation requires %#x access, but surface only has %#x.\n",
6632 required_access, surface->resource.access_flags);
6633 }
6634
6635 if (!(surface->flags & SFLAG_LOCATIONS))
6636 {
6637 ERR("Surface %p does not have any up to date location.\n", surface);
6638 surface->flags |= SFLAG_LOST;
6639 return WINED3DERR_DEVICELOST;
6640 }
6641
6642 switch (location)
6643 {
6644 case SFLAG_INSYSMEM:
6645 surface_load_sysmem(surface, gl_info, rect);
6646 break;
6647
6648 case SFLAG_INDRAWABLE:
6649 if (FAILED(hr = surface_load_drawable(surface, gl_info, rect)))
6650 return hr;
6651 break;
6652
6653 case SFLAG_INRB_RESOLVED:
6654 surface_multisample_resolve(surface);
6655 break;
6656
6657 case SFLAG_INTEXTURE:
6658 case SFLAG_INSRGBTEX:
6659 if (FAILED(hr = surface_load_texture(surface, gl_info, rect, location == SFLAG_INSRGBTEX)))
6660 return hr;
6661 break;
6662
6663 default:
6664 ERR("Don't know how to handle location %#x.\n", location);
6665 break;
6666 }
6667
6668#ifdef VBOX_WITH_WDDM
6669post_process:
6670
6671 if (VBOXSHRC_IS_SHARED_UNLOCKED(surface))
6672 {
6673 /* with the shared resource only texture can be considered valid
6674 * to make sure changes done to the resource in the other device context are visible
6675 * because the resource contents is shared via texture.
6676 * One can load and use other locations as needed,
6677 * but they should be reloaded each time on each usage */
6678 Assert(!!(surface->flags & SFLAG_INTEXTURE) || !!(location & SFLAG_INTEXTURE));
6679 surface->flags &= ~SFLAG_LOCATIONS;
6680 surface->flags |= SFLAG_INTEXTURE;
6681 /* @todo: SFLAG_INSRGBTEX ?? */
6682// if (in_fbo)
6683// {
6684// surface->flags |= SFLAG_INDRAWABLE;
6685// }
6686 }
6687 else if (surface->flags & SFLAG_CLIENTMEM)
6688 {
6689 Assert(!!(surface->flags & SFLAG_INSYSMEM));
6690 surface->flags &= ~SFLAG_LOCATIONS;
6691 surface->flags |= SFLAG_INSYSMEM;
6692 }
6693 else
6694#endif
6695 {
6696 if (!rect)
6697 {
6698 surface->flags |= location;
6699
6700 if (location != SFLAG_INSYSMEM && (surface->flags & SFLAG_INSYSMEM))
6701 surface_evict_sysmem(surface);
6702 }
6703
6704 if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)
6705 && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6706 {
6707 surface->flags |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX);
6708 }
6709 }
6710
6711 return WINED3D_OK;
6712}
6713
6714BOOL surface_is_offscreen(const struct wined3d_surface *surface)
6715{
6716 struct wined3d_swapchain *swapchain;
6717
6718 /* Not on a swapchain - must be offscreen */
6719 if (!(swapchain = surface->swapchain))
6720 return TRUE;
6721
6722 /* The front buffer is always onscreen */
6723 if (surface == swapchain->front_buffer) return FALSE;
6724
6725 /* If the swapchain is rendered to an FBO, the backbuffer is
6726 * offscreen, otherwise onscreen */
6727 return swapchain->render_to_fbo;
6728}
6729
6730static HRESULT ffp_blit_alloc(struct wined3d_device *device) { return WINED3D_OK; }
6731/* Context activation is done by the caller. */
6732static void ffp_blit_free(struct wined3d_device *device) { }
6733
6734/* This function is used in case of 8bit paletted textures using GL_EXT_paletted_texture */
6735/* Context activation is done by the caller. */
6736static void ffp_blit_p8_upload_palette(const struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
6737{
6738 BYTE table[256][4];
6739 BOOL colorkey_active = (surface->CKeyFlags & WINEDDSD_CKSRCBLT) != 0;
6740 GLenum target;
6741
6742 if (surface->container)
6743 target = surface->container->target;
6744 else
6745 target = surface->texture_target;
6746
6747 d3dfmt_p8_init_palette(surface, table, colorkey_active);
6748
6749 TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n");
6750 GL_EXTCALL(glColorTableEXT(target, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, table));
6751}
6752
6753/* Context activation is done by the caller. */
6754static HRESULT ffp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
6755{
6756 enum complex_fixup fixup = get_complex_fixup(surface->resource.format->color_fixup);
6757 const struct wined3d_gl_info *gl_info = context->gl_info;
6758 GLenum target;
6759
6760 if (surface->container)
6761 target = surface->container->target;
6762 else
6763 target = surface->texture_target;
6764
6765 /* When EXT_PALETTED_TEXTURE is around, palette conversion is done by the GPU
6766 * else the surface is converted in software at upload time in LoadLocation.
6767 */
6768 if (!(surface->flags & SFLAG_CONVERTED) && fixup == COMPLEX_FIXUP_P8
6769 && gl_info->supported[EXT_PALETTED_TEXTURE])
6770 ffp_blit_p8_upload_palette(surface, gl_info);
6771
6772 gl_info->gl_ops.gl.p_glEnable(target);
6773 checkGLcall("glEnable(target)");
6774 return WINED3D_OK;
6775}
6776
6777/* Context activation is done by the caller. */
6778static void ffp_blit_unset(const struct wined3d_gl_info *gl_info)
6779{
6780 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
6781 checkGLcall("glDisable(GL_TEXTURE_2D)");
6782 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
6783 {
6784 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
6785 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
6786 }
6787 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
6788 {
6789 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
6790 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
6791 }
6792}
6793
6794static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
6795 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
6796 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
6797{
6798 enum complex_fixup src_fixup;
6799
6800 switch (blit_op)
6801 {
6802 case WINED3D_BLIT_OP_COLOR_BLIT:
6803 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
6804 return FALSE;
6805
6806 src_fixup = get_complex_fixup(src_format->color_fixup);
6807 if (TRACE_ON(d3d_surface) && TRACE_ON(d3d))
6808 {
6809 TRACE("Checking support for fixup:\n");
6810 dump_color_fixup_desc(src_format->color_fixup);
6811 }
6812
6813 if (!is_identity_fixup(dst_format->color_fixup))
6814 {
6815 TRACE("Destination fixups are not supported\n");
6816 return FALSE;
6817 }
6818
6819 if (src_fixup == COMPLEX_FIXUP_P8 && gl_info->supported[EXT_PALETTED_TEXTURE])
6820 {
6821 TRACE("P8 fixup supported\n");
6822 return TRUE;
6823 }
6824
6825 /* We only support identity conversions. */
6826 if (is_identity_fixup(src_format->color_fixup))
6827 {
6828 TRACE("[OK]\n");
6829 return TRUE;
6830 }
6831
6832 TRACE("[FAILED]\n");
6833 return FALSE;
6834
6835 case WINED3D_BLIT_OP_COLOR_FILL:
6836 if (dst_pool == WINED3D_POOL_SYSTEM_MEM)
6837 return FALSE;
6838
6839 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6840 {
6841 if (!((dst_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
6842 return FALSE;
6843 }
6844 else if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
6845 {
6846 TRACE("Color fill not supported\n");
6847 return FALSE;
6848 }
6849
6850 /* FIXME: We should reject color fills on formats with fixups,
6851 * but this would break P8 color fills for example. */
6852
6853 return TRUE;
6854
6855 case WINED3D_BLIT_OP_DEPTH_FILL:
6856 return TRUE;
6857
6858 default:
6859 TRACE("Unsupported blit_op=%d\n", blit_op);
6860 return FALSE;
6861 }
6862}
6863
6864/* Do not call while under the GL lock. */
6865static HRESULT ffp_blit_color_fill(struct wined3d_device *device, struct wined3d_surface *dst_surface,
6866 const RECT *dst_rect, const struct wined3d_color *color)
6867{
6868 const RECT draw_rect = {0, 0, dst_surface->resource.width, dst_surface->resource.height};
6869 struct wined3d_fb_state fb = {&dst_surface, NULL};
6870
6871 device_clear_render_targets(device, 1, &fb, 1, dst_rect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
6872
6873 return WINED3D_OK;
6874}
6875
6876/* Do not call while under the GL lock. */
6877static HRESULT ffp_blit_depth_fill(struct wined3d_device *device,
6878 struct wined3d_surface *surface, const RECT *rect, float depth)
6879{
6880 const RECT draw_rect = {0, 0, surface->resource.width, surface->resource.height};
6881 struct wined3d_fb_state fb = {NULL, surface};
6882
6883 device_clear_render_targets(device, 0, &fb, 1, rect, &draw_rect, WINED3DCLEAR_ZBUFFER, 0, depth, 0);
6884
6885 return WINED3D_OK;
6886}
6887
6888const struct blit_shader ffp_blit = {
6889 ffp_blit_alloc,
6890 ffp_blit_free,
6891 ffp_blit_set,
6892 ffp_blit_unset,
6893 ffp_blit_supported,
6894 ffp_blit_color_fill,
6895 ffp_blit_depth_fill,
6896};
6897
6898static HRESULT cpu_blit_alloc(struct wined3d_device *device)
6899{
6900 return WINED3D_OK;
6901}
6902
6903/* Context activation is done by the caller. */
6904static void cpu_blit_free(struct wined3d_device *device)
6905{
6906}
6907
6908/* Context activation is done by the caller. */
6909static HRESULT cpu_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
6910{
6911 return WINED3D_OK;
6912}
6913
6914/* Context activation is done by the caller. */
6915static void cpu_blit_unset(const struct wined3d_gl_info *gl_info)
6916{
6917}
6918
6919static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
6920 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
6921 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
6922{
6923 if (blit_op == WINED3D_BLIT_OP_COLOR_FILL)
6924 {
6925 return TRUE;
6926 }
6927
6928 return FALSE;
6929}
6930
6931static HRESULT surface_cpu_blt_compressed(const BYTE *src_data, BYTE *dst_data,
6932 UINT src_pitch, UINT dst_pitch, UINT update_w, UINT update_h,
6933 const struct wined3d_format *format, DWORD flags, const WINEDDBLTFX *fx)
6934{
6935 UINT row_block_count;
6936 const BYTE *src_row;
6937 BYTE *dst_row;
6938 UINT x, y;
6939
6940 src_row = src_data;
6941 dst_row = dst_data;
6942
6943 row_block_count = (update_w + format->block_width - 1) / format->block_width;
6944
6945 if (!flags)
6946 {
6947 for (y = 0; y < update_h; y += format->block_height)
6948 {
6949 memcpy(dst_row, src_row, row_block_count * format->block_byte_count);
6950 src_row += src_pitch;
6951 dst_row += dst_pitch;
6952 }
6953
6954 return WINED3D_OK;
6955 }
6956
6957 if (flags == WINEDDBLT_DDFX && fx->dwDDFX == WINEDDBLTFX_MIRRORUPDOWN)
6958 {
6959 src_row += (((update_h / format->block_height) - 1) * src_pitch);
6960
6961 switch (format->id)
6962 {
6963 case WINED3DFMT_DXT1:
6964 for (y = 0; y < update_h; y += format->block_height)
6965 {
6966 struct block
6967 {
6968 WORD color[2];
6969 BYTE control_row[4];
6970 };
6971
6972 const struct block *s = (const struct block *)src_row;
6973 struct block *d = (struct block *)dst_row;
6974
6975 for (x = 0; x < row_block_count; ++x)
6976 {
6977 d[x].color[0] = s[x].color[0];
6978 d[x].color[1] = s[x].color[1];
6979 d[x].control_row[0] = s[x].control_row[3];
6980 d[x].control_row[1] = s[x].control_row[2];
6981 d[x].control_row[2] = s[x].control_row[1];
6982 d[x].control_row[3] = s[x].control_row[0];
6983 }
6984 src_row -= src_pitch;
6985 dst_row += dst_pitch;
6986 }
6987 return WINED3D_OK;
6988
6989 case WINED3DFMT_DXT3:
6990 for (y = 0; y < update_h; y += format->block_height)
6991 {
6992 struct block
6993 {
6994 WORD alpha_row[4];
6995 WORD color[2];
6996 BYTE control_row[4];
6997 };
6998
6999 const struct block *s = (const struct block *)src_row;
7000 struct block *d = (struct block *)dst_row;
7001
7002 for (x = 0; x < row_block_count; ++x)
7003 {
7004 d[x].alpha_row[0] = s[x].alpha_row[3];
7005 d[x].alpha_row[1] = s[x].alpha_row[2];
7006 d[x].alpha_row[2] = s[x].alpha_row[1];
7007 d[x].alpha_row[3] = s[x].alpha_row[0];
7008 d[x].color[0] = s[x].color[0];
7009 d[x].color[1] = s[x].color[1];
7010 d[x].control_row[0] = s[x].control_row[3];
7011 d[x].control_row[1] = s[x].control_row[2];
7012 d[x].control_row[2] = s[x].control_row[1];
7013 d[x].control_row[3] = s[x].control_row[0];
7014 }
7015 src_row -= src_pitch;
7016 dst_row += dst_pitch;
7017 }
7018 return WINED3D_OK;
7019
7020 default:
7021 FIXME("Compressed flip not implemented for format %s.\n",
7022 debug_d3dformat(format->id));
7023 return E_NOTIMPL;
7024 }
7025 }
7026
7027 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
7028 debug_d3dformat(format->id), flags, flags & WINEDDBLT_DDFX ? fx->dwDDFX : 0);
7029
7030 return E_NOTIMPL;
7031}
7032
7033static HRESULT surface_cpu_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
7034 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
7035 const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter)
7036{
7037 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
7038 const struct wined3d_format *src_format, *dst_format;
7039 struct wined3d_surface *orig_src = src_surface;
7040 struct wined3d_map_desc dst_map, src_map;
7041 const BYTE *sbase = NULL;
7042 HRESULT hr = WINED3D_OK;
7043 const BYTE *sbuf;
7044 BYTE *dbuf;
7045 int x, y;
7046
7047 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
7048 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
7049 flags, fx, debug_d3dtexturefiltertype(filter));
7050
7051 if (src_surface == dst_surface)
7052 {
7053 wined3d_surface_map(dst_surface, &dst_map, NULL, 0);
7054 src_map = dst_map;
7055 src_format = dst_surface->resource.format;
7056 dst_format = src_format;
7057 }
7058 else
7059 {
7060 dst_format = dst_surface->resource.format;
7061 if (src_surface)
7062 {
7063 if (dst_surface->resource.format->id != src_surface->resource.format->id)
7064 {
7065 src_surface = surface_convert_format(src_surface, dst_format->id);
7066 if (!src_surface)
7067 {
7068 /* The conv function writes a FIXME */
7069 WARN("Cannot convert source surface format to dest format.\n");
7070 goto release;
7071 }
7072 }
7073 wined3d_surface_map(src_surface, &src_map, NULL, WINED3D_MAP_READONLY);
7074 src_format = src_surface->resource.format;
7075 }
7076 else
7077 {
7078 src_format = dst_format;
7079 }
7080
7081 wined3d_surface_map(dst_surface, &dst_map, dst_rect, 0);
7082 }
7083
7084 bpp = dst_surface->resource.format->byte_count;
7085 srcheight = src_rect->bottom - src_rect->top;
7086 srcwidth = src_rect->right - src_rect->left;
7087 dstheight = dst_rect->bottom - dst_rect->top;
7088 dstwidth = dst_rect->right - dst_rect->left;
7089 width = (dst_rect->right - dst_rect->left) * bpp;
7090
7091 if (src_surface)
7092 sbase = (BYTE *)src_map.data
7093 + ((src_rect->top / src_format->block_height) * src_map.row_pitch)
7094 + ((src_rect->left / src_format->block_width) * src_format->block_byte_count);
7095 if (src_surface != dst_surface)
7096 dbuf = dst_map.data;
7097 else
7098 dbuf = (BYTE *)dst_map.data
7099 + ((dst_rect->top / dst_format->block_height) * dst_map.row_pitch)
7100 + ((dst_rect->left / dst_format->block_width) * dst_format->block_byte_count);
7101
7102 if (src_format->flags & dst_format->flags & WINED3DFMT_FLAG_BLOCKS)
7103 {
7104 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
7105
7106 if (src_surface == dst_surface)
7107 {
7108 FIXME("Only plain blits supported on compressed surfaces.\n");
7109 hr = E_NOTIMPL;
7110 goto release;
7111 }
7112
7113 if (srcheight != dstheight || srcwidth != dstwidth)
7114 {
7115 WARN("Stretching not supported on compressed surfaces.\n");
7116 hr = WINED3DERR_INVALIDCALL;
7117 goto release;
7118 }
7119
7120 if (!surface_check_block_align(src_surface, src_rect))
7121 {
7122 WARN("Source rectangle not block-aligned.\n");
7123 hr = WINED3DERR_INVALIDCALL;
7124 goto release;
7125 }
7126
7127 if (!surface_check_block_align(dst_surface, dst_rect))
7128 {
7129 WARN("Destination rectangle not block-aligned.\n");
7130 hr = WINED3DERR_INVALIDCALL;
7131 goto release;
7132 }
7133
7134 hr = surface_cpu_blt_compressed(sbase, dbuf,
7135 src_map.row_pitch, dst_map.row_pitch, dstwidth, dstheight,
7136 src_format, flags, fx);
7137 goto release;
7138 }
7139
7140 /* First, all the 'source-less' blits */
7141 if (flags & WINEDDBLT_COLORFILL)
7142 {
7143 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, fx->u5.dwFillColor);
7144 flags &= ~WINEDDBLT_COLORFILL;
7145 }
7146
7147 if (flags & WINEDDBLT_DEPTHFILL)
7148 {
7149 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
7150 }
7151 if (flags & WINEDDBLT_ROP)
7152 {
7153 /* Catch some degenerate cases here. */
7154 switch (fx->dwROP)
7155 {
7156 case BLACKNESS:
7157 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, 0);
7158 break;
7159 case 0xaa0029: /* No-op */
7160 break;
7161 case WHITENESS:
7162 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, ~0U);
7163 break;
7164 case SRCCOPY: /* Well, we do that below? */
7165 break;
7166 default:
7167 FIXME("Unsupported raster op: %08x Pattern: %p\n", fx->dwROP, fx->u5.lpDDSPattern);
7168 goto error;
7169 }
7170 flags &= ~WINEDDBLT_ROP;
7171 }
7172 if (flags & WINEDDBLT_DDROPS)
7173 {
7174 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", fx->dwDDROP, fx->u5.lpDDSPattern);
7175 }
7176 /* Now the 'with source' blits. */
7177 if (src_surface)
7178 {
7179 int sx, xinc, sy, yinc;
7180
7181 if (!dstwidth || !dstheight) /* Hmm... stupid program? */
7182 goto release;
7183
7184 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT
7185 && (srcwidth != dstwidth || srcheight != dstheight))
7186 {
7187 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
7188 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter));
7189 }
7190
7191 xinc = (srcwidth << 16) / dstwidth;
7192 yinc = (srcheight << 16) / dstheight;
7193
7194 if (!flags)
7195 {
7196 /* No effects, we can cheat here. */
7197 if (dstwidth == srcwidth)
7198 {
7199 if (dstheight == srcheight)
7200 {
7201 /* No stretching in either direction. This needs to be as
7202 * fast as possible. */
7203 sbuf = sbase;
7204
7205 /* Check for overlapping surfaces. */
7206 if (src_surface != dst_surface || dst_rect->top < src_rect->top
7207 || dst_rect->right <= src_rect->left || src_rect->right <= dst_rect->left)
7208 {
7209 /* No overlap, or dst above src, so copy from top downwards. */
7210 for (y = 0; y < dstheight; ++y)
7211 {
7212 memcpy(dbuf, sbuf, width);
7213 sbuf += src_map.row_pitch;
7214 dbuf += dst_map.row_pitch;
7215 }
7216 }
7217 else if (dst_rect->top > src_rect->top)
7218 {
7219 /* Copy from bottom upwards. */
7220 sbuf += src_map.row_pitch * dstheight;
7221 dbuf += dst_map.row_pitch * dstheight;
7222 for (y = 0; y < dstheight; ++y)
7223 {
7224 sbuf -= src_map.row_pitch;
7225 dbuf -= dst_map.row_pitch;
7226 memcpy(dbuf, sbuf, width);
7227 }
7228 }
7229 else
7230 {
7231 /* Src and dst overlapping on the same line, use memmove. */
7232 for (y = 0; y < dstheight; ++y)
7233 {
7234 memmove(dbuf, sbuf, width);
7235 sbuf += src_map.row_pitch;
7236 dbuf += dst_map.row_pitch;
7237 }
7238 }
7239 }
7240 else
7241 {
7242 /* Stretching in y direction only. */
7243 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
7244 {
7245 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
7246 memcpy(dbuf, sbuf, width);
7247 dbuf += dst_map.row_pitch;
7248 }
7249 }
7250 }
7251 else
7252 {
7253 /* Stretching in X direction. */
7254 int last_sy = -1;
7255 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
7256 {
7257 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
7258
7259 if ((sy >> 16) == (last_sy >> 16))
7260 {
7261 /* This source row is the same as last source row -
7262 * Copy the already stretched row. */
7263 memcpy(dbuf, dbuf - dst_map.row_pitch, width);
7264 }
7265 else
7266 {
7267#define STRETCH_ROW(type) \
7268do { \
7269 const type *s = (const type *)sbuf; \
7270 type *d = (type *)dbuf; \
7271 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
7272 d[x] = s[sx >> 16]; \
7273} while(0)
7274
7275 switch(bpp)
7276 {
7277 case 1:
7278 STRETCH_ROW(BYTE);
7279 break;
7280 case 2:
7281 STRETCH_ROW(WORD);
7282 break;
7283 case 4:
7284 STRETCH_ROW(DWORD);
7285 break;
7286 case 3:
7287 {
7288 const BYTE *s;
7289 BYTE *d = dbuf;
7290 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
7291 {
7292 DWORD pixel;
7293
7294 s = sbuf + 3 * (sx >> 16);
7295 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
7296 d[0] = (pixel ) & 0xff;
7297 d[1] = (pixel >> 8) & 0xff;
7298 d[2] = (pixel >> 16) & 0xff;
7299 d += 3;
7300 }
7301 break;
7302 }
7303 default:
7304 FIXME("Stretched blit not implemented for bpp %u!\n", bpp * 8);
7305 hr = WINED3DERR_NOTAVAILABLE;
7306 goto error;
7307 }
7308#undef STRETCH_ROW
7309 }
7310 dbuf += dst_map.row_pitch;
7311 last_sy = sy;
7312 }
7313 }
7314 }
7315 else
7316 {
7317 LONG dstyinc = dst_map.row_pitch, dstxinc = bpp;
7318 DWORD keylow = 0xffffffff, keyhigh = 0, keymask = 0xffffffff;
7319 DWORD destkeylow = 0x0, destkeyhigh = 0xffffffff, destkeymask = 0xffffffff;
7320 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
7321 {
7322 /* The color keying flags are checked for correctness in ddraw */
7323 if (flags & WINEDDBLT_KEYSRC)
7324 {
7325 keylow = src_surface->src_blt_color_key.color_space_low_value;
7326 keyhigh = src_surface->src_blt_color_key.color_space_high_value;
7327 }
7328 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
7329 {
7330 keylow = fx->ddckSrcColorkey.color_space_low_value;
7331 keyhigh = fx->ddckSrcColorkey.color_space_high_value;
7332 }
7333
7334 if (flags & WINEDDBLT_KEYDEST)
7335 {
7336 /* Destination color keys are taken from the source surface! */
7337 destkeylow = src_surface->dst_blt_color_key.color_space_low_value;
7338 destkeyhigh = src_surface->dst_blt_color_key.color_space_high_value;
7339 }
7340 else if (flags & WINEDDBLT_KEYDESTOVERRIDE)
7341 {
7342 destkeylow = fx->ddckDestColorkey.color_space_low_value;
7343 destkeyhigh = fx->ddckDestColorkey.color_space_high_value;
7344 }
7345
7346 if (bpp == 1)
7347 {
7348 keymask = 0xff;
7349 }
7350 else
7351 {
7352 DWORD masks[3];
7353 get_color_masks(src_format, masks);
7354 keymask = masks[0]
7355 | masks[1]
7356 | masks[2];
7357 }
7358 flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
7359 }
7360
7361 if (flags & WINEDDBLT_DDFX)
7362 {
7363 BYTE *dTopLeft, *dTopRight, *dBottomLeft, *dBottomRight, *tmp;
7364 LONG tmpxy;
7365 dTopLeft = dbuf;
7366 dTopRight = dbuf + ((dstwidth - 1) * bpp);
7367 dBottomLeft = dTopLeft + ((dstheight - 1) * dst_map.row_pitch);
7368 dBottomRight = dBottomLeft + ((dstwidth - 1) * bpp);
7369
7370 if (fx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
7371 {
7372 /* I don't think we need to do anything about this flag */
7373 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
7374 }
7375 if (fx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
7376 {
7377 tmp = dTopRight;
7378 dTopRight = dTopLeft;
7379 dTopLeft = tmp;
7380 tmp = dBottomRight;
7381 dBottomRight = dBottomLeft;
7382 dBottomLeft = tmp;
7383 dstxinc = dstxinc * -1;
7384 }
7385 if (fx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
7386 {
7387 tmp = dTopLeft;
7388 dTopLeft = dBottomLeft;
7389 dBottomLeft = tmp;
7390 tmp = dTopRight;
7391 dTopRight = dBottomRight;
7392 dBottomRight = tmp;
7393 dstyinc = dstyinc * -1;
7394 }
7395 if (fx->dwDDFX & WINEDDBLTFX_NOTEARING)
7396 {
7397 /* I don't think we need to do anything about this flag */
7398 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
7399 }
7400 if (fx->dwDDFX & WINEDDBLTFX_ROTATE180)
7401 {
7402 tmp = dBottomRight;
7403 dBottomRight = dTopLeft;
7404 dTopLeft = tmp;
7405 tmp = dBottomLeft;
7406 dBottomLeft = dTopRight;
7407 dTopRight = tmp;
7408 dstxinc = dstxinc * -1;
7409 dstyinc = dstyinc * -1;
7410 }
7411 if (fx->dwDDFX & WINEDDBLTFX_ROTATE270)
7412 {
7413 tmp = dTopLeft;
7414 dTopLeft = dBottomLeft;
7415 dBottomLeft = dBottomRight;
7416 dBottomRight = dTopRight;
7417 dTopRight = tmp;
7418 tmpxy = dstxinc;
7419 dstxinc = dstyinc;
7420 dstyinc = tmpxy;
7421 dstxinc = dstxinc * -1;
7422 }
7423 if (fx->dwDDFX & WINEDDBLTFX_ROTATE90)
7424 {
7425 tmp = dTopLeft;
7426 dTopLeft = dTopRight;
7427 dTopRight = dBottomRight;
7428 dBottomRight = dBottomLeft;
7429 dBottomLeft = tmp;
7430 tmpxy = dstxinc;
7431 dstxinc = dstyinc;
7432 dstyinc = tmpxy;
7433 dstyinc = dstyinc * -1;
7434 }
7435 if (fx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
7436 {
7437 /* I don't think we need to do anything about this flag */
7438 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
7439 }
7440 dbuf = dTopLeft;
7441 flags &= ~(WINEDDBLT_DDFX);
7442 }
7443
7444#define COPY_COLORKEY_FX(type) \
7445do { \
7446 const type *s; \
7447 type *d = (type *)dbuf, *dx, tmp; \
7448 for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
7449 { \
7450 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
7451 dx = d; \
7452 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
7453 { \
7454 tmp = s[sx >> 16]; \
7455 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
7456 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
7457 { \
7458 dx[0] = tmp; \
7459 } \
7460 dx = (type *)(((BYTE *)dx) + dstxinc); \
7461 } \
7462 d = (type *)(((BYTE *)d) + dstyinc); \
7463 } \
7464} while(0)
7465
7466 switch (bpp)
7467 {
7468 case 1:
7469 COPY_COLORKEY_FX(BYTE);
7470 break;
7471 case 2:
7472 COPY_COLORKEY_FX(WORD);
7473 break;
7474 case 4:
7475 COPY_COLORKEY_FX(DWORD);
7476 break;
7477 case 3:
7478 {
7479 const BYTE *s;
7480 BYTE *d = dbuf, *dx;
7481 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
7482 {
7483 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
7484 dx = d;
7485 for (x = sx = 0; x < dstwidth; ++x, sx+= xinc)
7486 {
7487 DWORD pixel, dpixel = 0;
7488 s = sbuf + 3 * (sx>>16);
7489 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
7490 dpixel = dx[0] | (dx[1] << 8 ) | (dx[2] << 16);
7491 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
7492 && ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
7493 {
7494 dx[0] = (pixel ) & 0xff;
7495 dx[1] = (pixel >> 8) & 0xff;
7496 dx[2] = (pixel >> 16) & 0xff;
7497 }
7498 dx += dstxinc;
7499 }
7500 d += dstyinc;
7501 }
7502 break;
7503 }
7504 default:
7505 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
7506 (flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp * 8);
7507 hr = WINED3DERR_NOTAVAILABLE;
7508 goto error;
7509#undef COPY_COLORKEY_FX
7510 }
7511 }
7512 }
7513
7514error:
7515 if (flags && FIXME_ON(d3d_surface))
7516 {
7517 FIXME("\tUnsupported flags: %#x.\n", flags);
7518 }
7519
7520release:
7521 wined3d_surface_unmap(dst_surface);
7522 if (src_surface && src_surface != dst_surface)
7523 wined3d_surface_unmap(src_surface);
7524 /* Release the converted surface, if any. */
7525 if (src_surface && src_surface != orig_src)
7526 wined3d_surface_decref(src_surface);
7527
7528 return hr;
7529}
7530
7531/* Do not call while under the GL lock. */
7532static HRESULT cpu_blit_color_fill(struct wined3d_device *device, struct wined3d_surface *dst_surface,
7533 const RECT *dst_rect, const struct wined3d_color *color)
7534{
7535 static const RECT src_rect;
7536 WINEDDBLTFX BltFx;
7537
7538 memset(&BltFx, 0, sizeof(BltFx));
7539 BltFx.dwSize = sizeof(BltFx);
7540 BltFx.u5.dwFillColor = wined3d_format_convert_from_float(dst_surface, color);
7541 return surface_cpu_blt(dst_surface, dst_rect, NULL, &src_rect,
7542 WINEDDBLT_COLORFILL, &BltFx, WINED3D_TEXF_POINT);
7543}
7544
7545/* Do not call while under the GL lock. */
7546static HRESULT cpu_blit_depth_fill(struct wined3d_device *device,
7547 struct wined3d_surface *surface, const RECT *rect, float depth)
7548{
7549 FIXME("Depth filling not implemented by cpu_blit.\n");
7550 return WINED3DERR_INVALIDCALL;
7551}
7552
7553const struct blit_shader cpu_blit = {
7554 cpu_blit_alloc,
7555 cpu_blit_free,
7556 cpu_blit_set,
7557 cpu_blit_unset,
7558 cpu_blit_supported,
7559 cpu_blit_color_fill,
7560 cpu_blit_depth_fill,
7561};
7562
7563static HRESULT surface_init(struct wined3d_surface *surface, UINT alignment, UINT width, UINT height,
7564 enum wined3d_multisample_type multisample_type, UINT multisample_quality,
7565 struct wined3d_device *device, DWORD usage, enum wined3d_format_id format_id,
7566 enum wined3d_pool pool, DWORD flags, void *parent, const struct wined3d_parent_ops *parent_ops
7567#ifdef VBOX_WITH_WDDM
7568 , HANDLE *shared_handle
7569 , void *pvClientMem
7570#endif
7571 )
7572{
7573 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
7574 const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
7575 BOOL lockable = flags & WINED3D_SURFACE_MAPPABLE;
7576 unsigned int resource_size;
7577 HRESULT hr;
7578
7579 if (multisample_quality > 0)
7580 {
7581 FIXME("multisample_quality set to %u, substituting 0.\n", multisample_quality);
7582 multisample_quality = 0;
7583 }
7584
7585 /* Quick lockable sanity check.
7586 * TODO: remove this after surfaces, usage and lockability have been debugged properly
7587 * this function is too deep to need to care about things like this.
7588 * Levels need to be checked too, since they all affect what can be done. */
7589 switch (pool)
7590 {
7591 case WINED3D_POOL_SCRATCH:
7592 if (!lockable)
7593 {
7594 FIXME("Called with a pool of SCRATCH and a lockable of FALSE "
7595 "which are mutually exclusive, setting lockable to TRUE.\n");
7596 lockable = TRUE;
7597 }
7598 break;
7599
7600 case WINED3D_POOL_SYSTEM_MEM:
7601 if (!lockable)
7602 FIXME("Called with a pool of SYSTEMMEM and a lockable of FALSE, this is acceptable but unexpected.\n");
7603 break;
7604
7605 case WINED3D_POOL_MANAGED:
7606 if (usage & WINED3DUSAGE_DYNAMIC)
7607 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
7608 break;
7609
7610 case WINED3D_POOL_DEFAULT:
7611 if (lockable && !(usage & (WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
7612 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
7613 break;
7614
7615 default:
7616 FIXME("Unknown pool %#x.\n", pool);
7617 break;
7618 };
7619
7620 if (usage & WINED3DUSAGE_RENDERTARGET && pool != WINED3D_POOL_DEFAULT)
7621 FIXME("Trying to create a render target that isn't in the default pool.\n");
7622
7623 /* FIXME: Check that the format is supported by the device. */
7624
7625 resource_size = wined3d_format_calculate_size(format, alignment, width, height);
7626 if (!resource_size)
7627 return WINED3DERR_INVALIDCALL;
7628
7629 if (device->wined3d->flags & WINED3D_NO3D)
7630 surface->surface_ops = &gdi_surface_ops;
7631 else
7632 surface->surface_ops = &surface_ops;
7633
7634 hr = resource_init(&surface->resource, device, WINED3D_RTYPE_SURFACE, format,
7635 multisample_type, multisample_quality, usage, pool, width, height, 1,
7636 resource_size, parent, parent_ops, &surface_resource_ops
7637#ifdef VBOX_WITH_WDDM
7638 , shared_handle
7639 , pvClientMem
7640#endif
7641 );
7642 if (FAILED(hr))
7643 {
7644 WARN("Failed to initialize resource, returning %#x.\n", hr);
7645 return hr;
7646 }
7647
7648#ifdef VBOX_WITH_WDDM
7649 /* this will be a nop for the non-shared resource,
7650 * for the shared resource this will ensure the surface is initialized properly */
7651 surface_shrc_lock(surface);
7652#endif
7653
7654 /* "Standalone" surface. */
7655 surface_set_container(surface, NULL);
7656
7657 list_init(&surface->overlays);
7658
7659 /* Flags */
7660 surface->flags = SFLAG_NORMCOORD; /* Default to normalized coords. */
7661 if (flags & WINED3D_SURFACE_DISCARD)
7662 surface->flags |= SFLAG_DISCARD;
7663 if (flags & WINED3D_SURFACE_PIN_SYSMEM)
7664 surface->flags |= SFLAG_PIN_SYSMEM;
7665 if (lockable || format_id == WINED3DFMT_D16_LOCKABLE)
7666 surface->flags |= SFLAG_LOCKABLE;
7667 /* I'm not sure if this qualifies as a hack or as an optimization. It
7668 * seems reasonable to assume that lockable render targets will get
7669 * locked, so we might as well set SFLAG_DYNLOCK right at surface
7670 * creation. However, the other reason we want to do this is that several
7671 * ddraw applications access surface memory while the surface isn't
7672 * mapped. The SFLAG_DYNLOCK behaviour of keeping SYSMEM around for
7673 * future locks prevents these from crashing. */
7674 if (lockable && (usage & WINED3DUSAGE_RENDERTARGET))
7675 surface->flags |= SFLAG_DYNLOCK;
7676#ifdef VBOX_WITH_WDDM
7677 if (pool == WINED3D_POOL_SYSTEM_MEM && pvClientMem) surface->flags |= SFLAG_CLIENTMEM;
7678#endif
7679
7680 /* Mark the texture as dirty so that it gets loaded first time around. */
7681 surface_add_dirty_rect(surface, NULL);
7682 list_init(&surface->renderbuffers);
7683
7684 TRACE("surface %p, memory %p, size %u\n",
7685 surface, surface->resource.allocatedMemory, surface->resource.size);
7686
7687 /* Call the private setup routine */
7688 hr = surface->surface_ops->surface_private_setup(surface);
7689 if (FAILED(hr))
7690 {
7691 ERR("Private setup failed, returning %#x\n", hr);
7692 surface_cleanup(surface);
7693 return hr;
7694 }
7695
7696 /* Similar to lockable rendertargets above, creating the DIB section
7697 * during surface initialization prevents the sysmem pointer from changing
7698 * after a wined3d_surface_getdc() call. */
7699 if ((usage & WINED3DUSAGE_OWNDC) && !surface->hDC
7700 && SUCCEEDED(surface_create_dib_section(surface)))
7701 {
7702 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7703 surface->resource.heapMemory = NULL;
7704 surface->resource.allocatedMemory = surface->dib.bitmap_data;
7705 }
7706
7707#ifdef VBOX_WITH_WDDM
7708 if (VBOXSHRC_IS_SHARED(surface))
7709 {
7710 Assert(shared_handle);
7711 if (!VBOXSHRC_IS_SHARED_OPENED(surface))
7712 {
7713 surface_shrc_unlock(surface);
7714 Assert(!(*shared_handle));
7715 *shared_handle = VBOXSHRC_GET_SHAREHANDLE(surface);
7716 pglChromiumParameteriCR(GL_PIN_TEXTURE_SET_CR, (GLuint)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.

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