VirtualBox

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

最後變更 在這個檔案從46521是 46521,由 vboxsync 提交於 12 年 前

wine/new: export

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

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