winex11: Ignore rectangles with invalid coordinates when converting region data.
[wine] / dlls / d3d8 / surface.c
1 /*
2  * IDirect3DSurface8 implementation
3  *
4  * Copyright 2005 Oliver Stieber
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include <assert.h>
23 #include "d3d8_private.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(d3d8);
26
27 static inline IDirect3DSurface8Impl *impl_from_IDirect3DSurface8(IDirect3DSurface8 *iface)
28 {
29     return CONTAINING_RECORD(iface, IDirect3DSurface8Impl, IDirect3DSurface8_iface);
30 }
31
32 /* IDirect3DSurface8 IUnknown parts follow: */
33 static HRESULT WINAPI IDirect3DSurface8Impl_QueryInterface(IDirect3DSurface8 *iface, REFIID riid,
34         void **ppobj)
35 {
36     IDirect3DSurface8Impl *This = impl_from_IDirect3DSurface8(iface);
37
38     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), ppobj);
39
40     if (IsEqualGUID(riid, &IID_IUnknown)
41         || IsEqualGUID(riid, &IID_IDirect3DResource8)
42         || IsEqualGUID(riid, &IID_IDirect3DSurface8)) {
43         IUnknown_AddRef(iface);
44         *ppobj = This;
45         return S_OK;
46     }
47
48     WARN("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ppobj);
49     *ppobj = NULL;
50     return E_NOINTERFACE;
51 }
52
53 static ULONG WINAPI IDirect3DSurface8Impl_AddRef(IDirect3DSurface8 *iface)
54 {
55     IDirect3DSurface8Impl *This = impl_from_IDirect3DSurface8(iface);
56
57     TRACE("iface %p.\n", iface);
58
59     if (This->forwardReference) {
60         /* Forward refcounting */
61         TRACE("(%p) : Forwarding to %p\n", This, This->forwardReference);
62         return IUnknown_AddRef(This->forwardReference);
63     } else {
64         /* No container, handle our own refcounting */
65         ULONG ref = InterlockedIncrement(&This->ref);
66
67         TRACE("%p increasing refcount to %u.\n", iface, ref);
68
69         if (ref == 1)
70         {
71             if (This->parentDevice) IUnknown_AddRef(This->parentDevice);
72             wined3d_mutex_lock();
73             wined3d_surface_incref(This->wined3d_surface);
74             wined3d_mutex_unlock();
75         }
76
77         return ref;
78     }
79 }
80
81 static ULONG WINAPI IDirect3DSurface8Impl_Release(IDirect3DSurface8 *iface)
82 {
83     IDirect3DSurface8Impl *This = impl_from_IDirect3DSurface8(iface);
84
85     TRACE("iface %p.\n", iface);
86
87     if (This->forwardReference) {
88         /* Forward refcounting */
89         TRACE("(%p) : Forwarding to %p\n", This, This->forwardReference);
90         return IUnknown_Release(This->forwardReference);
91     } else {
92         /* No container, handle our own refcounting */
93         ULONG ref = InterlockedDecrement(&This->ref);
94
95         TRACE("%p decreasing refcount to %u.\n", iface, ref);
96
97         if (ref == 0) {
98             IDirect3DDevice8 *parentDevice = This->parentDevice;
99
100             /* Implicit surfaces are destroyed with the device, not if refcount reaches 0. */
101             wined3d_mutex_lock();
102             wined3d_surface_decref(This->wined3d_surface);
103             wined3d_mutex_unlock();
104
105             if (parentDevice) IDirect3DDevice8_Release(parentDevice);
106         }
107
108         return ref;
109     }
110 }
111
112 /* IDirect3DSurface8 IDirect3DResource8 Interface follow: */
113 static HRESULT WINAPI IDirect3DSurface8Impl_GetDevice(IDirect3DSurface8 *iface,
114         IDirect3DDevice8 **device)
115 {
116     IDirect3DSurface8Impl *This = impl_from_IDirect3DSurface8(iface);
117
118     TRACE("iface %p, device %p.\n", iface, device);
119
120     if (This->forwardReference)
121     {
122         IDirect3DResource8 *resource;
123         HRESULT hr;
124
125         hr = IUnknown_QueryInterface(This->forwardReference, &IID_IDirect3DResource8, (void **)&resource);
126         if (SUCCEEDED(hr))
127         {
128             hr = IDirect3DResource8_GetDevice(resource, device);
129             IDirect3DResource8_Release(resource);
130
131             TRACE("Returning device %p.\n", *device);
132         }
133
134         return hr;
135     }
136
137     *device = This->parentDevice;
138     IDirect3DDevice8_AddRef(*device);
139
140     TRACE("Returning device %p.\n", *device);
141
142     return D3D_OK;
143 }
144
145 static HRESULT WINAPI IDirect3DSurface8Impl_SetPrivateData(IDirect3DSurface8 *iface, REFGUID guid,
146         const void *data, DWORD data_size, DWORD flags)
147 {
148     IDirect3DSurface8Impl *surface = impl_from_IDirect3DSurface8(iface);
149     struct wined3d_resource *resource;
150     HRESULT hr;
151
152     TRACE("iface %p, guid %s, data %p, data_size %u, flags %#x.\n",
153             iface, debugstr_guid(guid), data, data_size, flags);
154
155     wined3d_mutex_lock();
156     resource = wined3d_surface_get_resource(surface->wined3d_surface);
157     hr = wined3d_resource_set_private_data(resource, guid, data, data_size, flags);
158     wined3d_mutex_unlock();
159
160     return hr;
161 }
162
163 static HRESULT WINAPI IDirect3DSurface8Impl_GetPrivateData(IDirect3DSurface8 *iface, REFGUID guid,
164         void *data, DWORD *data_size)
165 {
166     IDirect3DSurface8Impl *surface = impl_from_IDirect3DSurface8(iface);
167     struct wined3d_resource *resource;
168     HRESULT hr;
169
170     TRACE("iface %p, guid %s, data %p, data_size %p.\n",
171             iface, debugstr_guid(guid), data, data_size);
172
173     wined3d_mutex_lock();
174     resource = wined3d_surface_get_resource(surface->wined3d_surface);
175     hr = wined3d_resource_get_private_data(resource, guid, data, data_size);
176     wined3d_mutex_unlock();
177
178     return hr;
179 }
180
181 static HRESULT WINAPI IDirect3DSurface8Impl_FreePrivateData(IDirect3DSurface8 *iface, REFGUID guid)
182 {
183     IDirect3DSurface8Impl *surface = impl_from_IDirect3DSurface8(iface);
184     struct wined3d_resource *resource;
185     HRESULT hr;
186
187     TRACE("iface %p, guid %s.\n", iface, debugstr_guid(guid));
188
189     wined3d_mutex_lock();
190     resource = wined3d_surface_get_resource(surface->wined3d_surface);
191     hr = wined3d_resource_free_private_data(resource, guid);
192     wined3d_mutex_unlock();
193
194     return hr;
195 }
196
197 /* IDirect3DSurface8 Interface follow: */
198 static HRESULT WINAPI IDirect3DSurface8Impl_GetContainer(IDirect3DSurface8 *iface, REFIID riid,
199         void **ppContainer)
200 {
201     IDirect3DSurface8Impl *This = impl_from_IDirect3DSurface8(iface);
202     HRESULT res;
203
204     TRACE("iface %p, riid %s, container %p.\n", iface, debugstr_guid(riid), ppContainer);
205
206     if (!This->container) return E_NOINTERFACE;
207
208     res = IUnknown_QueryInterface(This->container, riid, ppContainer);
209
210     TRACE("(%p) : returning %p\n", This, *ppContainer);
211     return res;
212 }
213
214 static HRESULT WINAPI IDirect3DSurface8Impl_GetDesc(IDirect3DSurface8 *iface, D3DSURFACE_DESC *desc)
215 {
216     IDirect3DSurface8Impl *This = impl_from_IDirect3DSurface8(iface);
217     struct wined3d_resource_desc wined3d_desc;
218     struct wined3d_resource *wined3d_resource;
219
220     TRACE("iface %p, desc %p.\n", iface, desc);
221
222     wined3d_mutex_lock();
223     wined3d_resource = wined3d_surface_get_resource(This->wined3d_surface);
224     wined3d_resource_get_desc(wined3d_resource, &wined3d_desc);
225     wined3d_mutex_unlock();
226
227     desc->Format = d3dformat_from_wined3dformat(wined3d_desc.format);
228     desc->Type = wined3d_desc.resource_type;
229     desc->Usage = wined3d_desc.usage & WINED3DUSAGE_MASK;
230     desc->Pool = wined3d_desc.pool;
231     desc->Size = wined3d_desc.size;
232     desc->MultiSampleType = wined3d_desc.multisample_type;
233     desc->Width = wined3d_desc.width;
234     desc->Height = wined3d_desc.height;
235
236     return D3D_OK;
237 }
238
239 static HRESULT WINAPI IDirect3DSurface8Impl_LockRect(IDirect3DSurface8 *iface,
240         D3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD Flags)
241 {
242     IDirect3DSurface8Impl *This = impl_from_IDirect3DSurface8(iface);
243     HRESULT hr;
244
245     TRACE("iface %p, locked_rect %p, rect %p, flags %#x.\n", iface, pLockedRect, pRect, Flags);
246
247     wined3d_mutex_lock();
248     if (pRect) {
249         D3DSURFACE_DESC desc;
250         IDirect3DSurface8_GetDesc(iface, &desc);
251
252         if ((pRect->left < 0)
253                 || (pRect->top < 0)
254                 || (pRect->left >= pRect->right)
255                 || (pRect->top >= pRect->bottom)
256                 || (pRect->right > desc.Width)
257                 || (pRect->bottom > desc.Height)) {
258             WARN("Trying to lock an invalid rectangle, returning D3DERR_INVALIDCALL\n");
259             wined3d_mutex_unlock();
260
261             return D3DERR_INVALIDCALL;
262         }
263     }
264
265     hr = wined3d_surface_map(This->wined3d_surface, (struct wined3d_mapped_rect *)pLockedRect, pRect, Flags);
266     wined3d_mutex_unlock();
267
268     return hr;
269 }
270
271 static HRESULT WINAPI IDirect3DSurface8Impl_UnlockRect(IDirect3DSurface8 *iface)
272 {
273     IDirect3DSurface8Impl *This = impl_from_IDirect3DSurface8(iface);
274     HRESULT hr;
275
276     TRACE("iface %p.\n", iface);
277
278     wined3d_mutex_lock();
279     hr = wined3d_surface_unmap(This->wined3d_surface);
280     wined3d_mutex_unlock();
281
282     switch(hr)
283     {
284         case WINEDDERR_NOTLOCKED:       return D3DERR_INVALIDCALL;
285         default:                        return hr;
286     }
287 }
288
289 static const IDirect3DSurface8Vtbl Direct3DSurface8_Vtbl =
290 {
291     /* IUnknown */
292     IDirect3DSurface8Impl_QueryInterface,
293     IDirect3DSurface8Impl_AddRef,
294     IDirect3DSurface8Impl_Release,
295     /* IDirect3DResource8 */
296     IDirect3DSurface8Impl_GetDevice,
297     IDirect3DSurface8Impl_SetPrivateData,
298     IDirect3DSurface8Impl_GetPrivateData,
299     IDirect3DSurface8Impl_FreePrivateData,
300     /* IDirect3DSurface8 */
301     IDirect3DSurface8Impl_GetContainer,
302     IDirect3DSurface8Impl_GetDesc,
303     IDirect3DSurface8Impl_LockRect,
304     IDirect3DSurface8Impl_UnlockRect
305 };
306
307 static void STDMETHODCALLTYPE surface_wined3d_object_destroyed(void *parent)
308 {
309     HeapFree(GetProcessHeap(), 0, parent);
310 }
311
312 static const struct wined3d_parent_ops d3d8_surface_wined3d_parent_ops =
313 {
314     surface_wined3d_object_destroyed,
315 };
316
317 HRESULT surface_init(IDirect3DSurface8Impl *surface, IDirect3DDevice8Impl *device,
318         UINT width, UINT height, D3DFORMAT format, BOOL lockable, BOOL discard, UINT level,
319         DWORD usage, D3DPOOL pool, D3DMULTISAMPLE_TYPE multisample_type, DWORD multisample_quality)
320 {
321     DWORD flags = 0;
322     HRESULT hr;
323
324     surface->IDirect3DSurface8_iface.lpVtbl = &Direct3DSurface8_Vtbl;
325     surface->ref = 1;
326
327     /* FIXME: Check MAX bounds of MultisampleQuality. */
328     if (multisample_quality > 0)
329     {
330         FIXME("Multisample quality set to %u, substituting 0.\n", multisample_quality);
331         multisample_quality = 0;
332     }
333
334     if (lockable)
335         flags |= WINED3D_SURFACE_MAPPABLE;
336     if (discard)
337         flags |= WINED3D_SURFACE_DISCARD;
338
339     wined3d_mutex_lock();
340     hr = wined3d_surface_create(device->wined3d_device, width, height, wined3dformat_from_d3dformat(format),
341             level, usage & WINED3DUSAGE_MASK, (enum wined3d_pool)pool, multisample_type, multisample_quality,
342             WINED3D_SURFACE_TYPE_OPENGL, flags, surface, &d3d8_surface_wined3d_parent_ops, &surface->wined3d_surface);
343     wined3d_mutex_unlock();
344     if (FAILED(hr))
345     {
346         WARN("Failed to create wined3d surface, hr %#x.\n", hr);
347         return hr;
348     }
349
350     surface->parentDevice = &device->IDirect3DDevice8_iface;
351     IUnknown_AddRef(surface->parentDevice);
352
353     return D3D_OK;
354 }
355
356 IDirect3DSurface8Impl *unsafe_impl_from_IDirect3DSurface8(IDirect3DSurface8 *iface)
357 {
358     if (!iface)
359         return NULL;
360     assert(iface->lpVtbl == &Direct3DSurface8_Vtbl);
361
362     return impl_from_IDirect3DSurface8(iface);
363 }