xref: /aosp_15_r20/external/mesa3d/src/gallium/frontends/nine/texture9.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright 2011 Joakim Sindholt <[email protected]>
3  * SPDX-License-Identifier: MIT
4  */
5 
6 #include "c99_alloca.h"
7 
8 #include "device9.h"
9 #include "surface9.h"
10 #include "texture9.h"
11 #include "nine_helpers.h"
12 #include "nine_memory_helper.h"
13 #include "nine_pipe.h"
14 #include "nine_dump.h"
15 
16 #include "pipe/p_state.h"
17 #include "pipe/p_context.h"
18 #include "pipe/p_screen.h"
19 #include "util/u_inlines.h"
20 #include "util/u_resource.h"
21 
22 #define DBG_CHANNEL DBG_TEXTURE
23 
24 static HRESULT
NineTexture9_ctor(struct NineTexture9 * This,struct NineUnknownParams * pParams,UINT Width,UINT Height,UINT Levels,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,HANDLE * pSharedHandle)25 NineTexture9_ctor( struct NineTexture9 *This,
26                    struct NineUnknownParams *pParams,
27                    UINT Width, UINT Height, UINT Levels,
28                    DWORD Usage,
29                    D3DFORMAT Format,
30                    D3DPOOL Pool,
31                    HANDLE *pSharedHandle )
32 {
33     struct pipe_screen *screen = pParams->device->screen;
34     struct pipe_resource *info = &This->base.base.info;
35     enum pipe_format pf;
36     unsigned *level_offsets = NULL;
37     unsigned l;
38     D3DSURFACE_DESC sfdesc;
39     HRESULT hr;
40     struct nine_allocation *user_buffer = NULL, *user_buffer_for_level;
41 
42     This->base.base.base.device = pParams->device; /* Early fill this field in case of failure */
43 
44     DBG("(%p) Width=%u Height=%u Levels=%u Usage=%s Format=%s Pool=%s "
45         "pSharedHandle=%p\n", This, Width, Height, Levels,
46         nine_D3DUSAGE_to_str(Usage),
47         d3dformat_to_string(Format), nine_D3DPOOL_to_str(Pool), pSharedHandle);
48 
49     user_assert(Width && Height, D3DERR_INVALIDCALL);
50 
51     /* pSharedHandle: can be non-null for ex only.
52      * D3DPOOL_SYSTEMMEM: Levels must be 1
53      * D3DPOOL_DEFAULT: no restriction for Levels
54      * Other Pools are forbidden. */
55     user_assert(!pSharedHandle || pParams->device->ex, D3DERR_INVALIDCALL);
56     user_assert(!pSharedHandle ||
57                 (Pool == D3DPOOL_SYSTEMMEM && Levels == 1) ||
58                 Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL);
59 
60     user_assert(!(Usage & D3DUSAGE_AUTOGENMIPMAP) ||
61                 (Pool != D3DPOOL_SYSTEMMEM && Pool != D3DPOOL_SCRATCH && Levels <= 1),
62                 D3DERR_INVALIDCALL);
63 
64     /* TODO: implement pSharedHandle for D3DPOOL_DEFAULT (cross process
65      * buffer sharing).
66      *
67      * Gem names may have fit but they're depreciated and won't work on render-nodes.
68      * One solution is to use shm buffers. We would use a /dev/shm file, fill the first
69      * values to tell it is a nine buffer, the size, which function created it, etc,
70      * and then it would contain the data. The handle would be a number, corresponding to
71      * the file to read (/dev/shm/nine-share-4 for example would be 4).
72      *
73      * Wine just ignores the argument, which works only if the app creates the handle
74      * and won't use it. Instead of failing, we support that situation by putting an
75      * invalid handle, that we would fail to import. Please note that we don't advertise
76      * the flag indicating the support for that feature, but apps seem to not care.
77      */
78 
79     if (pSharedHandle && Pool == D3DPOOL_DEFAULT) {
80         if (!*pSharedHandle) {
81             DBG("Creating Texture with invalid handle. Importing will fail\n.");
82             *pSharedHandle = (HANDLE)1; /* Wine would keep it NULL */
83             pSharedHandle = NULL;
84         } else {
85             ERR("Application tries to use cross-process sharing feature. Nine "
86                 "doesn't support it");
87             return D3DERR_INVALIDCALL;
88         }
89     }
90 
91     if (Usage & D3DUSAGE_AUTOGENMIPMAP)
92         Levels = 0;
93 
94     pf = d3d9_to_pipe_format_checked(screen, Format, PIPE_TEXTURE_2D, 0,
95                                      PIPE_BIND_SAMPLER_VIEW, false,
96                                      Pool == D3DPOOL_SCRATCH);
97 
98     if (Format != D3DFMT_NULL && pf == PIPE_FORMAT_NONE)
99         return D3DERR_INVALIDCALL;
100 
101     if (compressed_format(Format)) {
102         const unsigned w = util_format_get_blockwidth(pf);
103         const unsigned h = util_format_get_blockheight(pf);
104 
105         user_assert(!(Width % w) && !(Height % h), D3DERR_INVALIDCALL);
106     }
107 
108     info->screen = screen;
109     info->target = PIPE_TEXTURE_2D;
110     info->format = pf;
111     info->width0 = Width;
112     info->height0 = Height;
113     info->depth0 = 1;
114     if (Levels)
115         info->last_level = Levels - 1;
116     else
117         info->last_level = util_logbase2(MAX2(Width, Height));
118     info->array_size = 1;
119     info->nr_samples = 0;
120     info->nr_storage_samples = 0;
121     info->bind = PIPE_BIND_SAMPLER_VIEW;
122     info->usage = PIPE_USAGE_DEFAULT;
123     info->flags = 0;
124 
125     if (Usage & D3DUSAGE_RENDERTARGET)
126         info->bind |= PIPE_BIND_RENDER_TARGET;
127     if (Usage & D3DUSAGE_DEPTHSTENCIL)
128         info->bind |= PIPE_BIND_DEPTH_STENCIL;
129 
130     if (Usage & D3DUSAGE_DYNAMIC) {
131         info->usage = PIPE_USAGE_DYNAMIC;
132     }
133 
134     if (Usage & D3DUSAGE_SOFTWAREPROCESSING)
135         DBG("Application asked for Software Vertex Processing, "
136             "but this is unimplemented\n");
137 
138     hr = NineBaseTexture9_ctor(&This->base, pParams, NULL, D3DRTYPE_TEXTURE, Format, Pool, Usage);
139     if (FAILED(hr))
140         return hr;
141     This->base.pstype = (Height == 1) ? 1 : 0;
142 
143     if (pSharedHandle && *pSharedHandle) { /* Pool == D3DPOOL_SYSTEMMEM */
144         user_buffer = nine_wrap_external_pointer(pParams->device->allocator, (void *)*pSharedHandle);
145         level_offsets = alloca(sizeof(unsigned) * This->base.level_count);
146         (void) nine_format_get_size_and_offsets(pf, level_offsets,
147                                                 Width, Height,
148                                                 This->base.level_count-1);
149     } else if (Pool != D3DPOOL_DEFAULT) {
150         level_offsets = alloca(sizeof(unsigned) * This->base.level_count);
151         user_buffer = nine_allocate(pParams->device->allocator,
152             nine_format_get_size_and_offsets(pf, level_offsets,
153                                              Width, Height,
154                                              This->base.level_count-1));
155         This->managed_buffer = user_buffer;
156         if (!This->managed_buffer)
157             return E_OUTOFMEMORY;
158     }
159 
160     This->surfaces = CALLOC(This->base.level_count, sizeof(*This->surfaces));
161     if (!This->surfaces)
162         return E_OUTOFMEMORY;
163 
164     /* Create all the surfaces right away.
165      * They manage backing storage, and transfers (LockRect) are deferred
166      * to them.
167      */
168     sfdesc.Format = Format;
169     sfdesc.Type = D3DRTYPE_SURFACE;
170     sfdesc.Usage = Usage;
171     sfdesc.Pool = Pool;
172     sfdesc.MultiSampleType = D3DMULTISAMPLE_NONE;
173     sfdesc.MultiSampleQuality = 0;
174 
175     for (l = 0; l < This->base.level_count; ++l) {
176         sfdesc.Width = u_minify(Width, l);
177         sfdesc.Height = u_minify(Height, l);
178         /* Some apps expect the memory to be allocated in
179          * continuous blocks */
180         user_buffer_for_level = user_buffer ?
181             nine_suballocate(pParams->device->allocator, user_buffer, level_offsets[l]) : NULL;
182 
183         hr = NineSurface9_new(This->base.base.base.device, NineUnknown(This),
184                               This->base.base.resource, user_buffer_for_level,
185                               D3DRTYPE_TEXTURE, l, 0,
186                               &sfdesc, &This->surfaces[l]);
187         if (FAILED(hr))
188             return hr;
189     }
190 
191     /* Textures start initially dirty */
192     This->dirty_rect.width = Width;
193     This->dirty_rect.height = Height;
194     This->dirty_rect.depth = 1; /* width == 0 means empty, depth stays 1 */
195 
196     if (pSharedHandle && !*pSharedHandle) {/* Pool == D3DPOOL_SYSTEMMEM */
197         *pSharedHandle = This->surfaces[0]->data;
198     }
199 
200     return D3D_OK;
201 }
202 
203 static void
NineTexture9_dtor(struct NineTexture9 * This)204 NineTexture9_dtor( struct NineTexture9 *This )
205 {
206     bool is_worker = nine_context_is_worker(This->base.base.base.device);
207     unsigned l;
208 
209     DBG("This=%p\n", This);
210 
211     if (This->surfaces) {
212         /* The surfaces should have 0 references and be unbound now. */
213         for (l = 0; l < This->base.level_count; ++l)
214             if (This->surfaces[l])
215                 NineUnknown_Destroy(&This->surfaces[l]->base.base);
216         FREE(This->surfaces);
217     }
218 
219     if (This->managed_buffer) {
220         if (is_worker)
221             nine_free_worker(This->base.base.base.device->allocator, This->managed_buffer);
222         else
223             nine_free(This->base.base.base.device->allocator, This->managed_buffer);
224     }
225 
226     NineBaseTexture9_dtor(&This->base);
227 }
228 
229 HRESULT NINE_WINAPI
NineTexture9_GetLevelDesc(struct NineTexture9 * This,UINT Level,D3DSURFACE_DESC * pDesc)230 NineTexture9_GetLevelDesc( struct NineTexture9 *This,
231                            UINT Level,
232                            D3DSURFACE_DESC *pDesc )
233 {
234     DBG("This=%p Level=%d pDesc=%p\n", This, Level, pDesc);
235 
236     user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL);
237     user_assert(pDesc, D3DERR_INVALIDCALL);
238 
239     *pDesc = This->surfaces[Level]->desc;
240 
241     return D3D_OK;
242 }
243 
244 HRESULT NINE_WINAPI
NineTexture9_GetSurfaceLevel(struct NineTexture9 * This,UINT Level,IDirect3DSurface9 ** ppSurfaceLevel)245 NineTexture9_GetSurfaceLevel( struct NineTexture9 *This,
246                               UINT Level,
247                               IDirect3DSurface9 **ppSurfaceLevel )
248 {
249     DBG("This=%p Level=%d ppSurfaceLevel=%p\n", This, Level, ppSurfaceLevel);
250 
251     user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL);
252     user_assert(ppSurfaceLevel, D3DERR_INVALIDCALL);
253 
254     NineUnknown_AddRef(NineUnknown(This->surfaces[Level]));
255     *ppSurfaceLevel = (IDirect3DSurface9 *)This->surfaces[Level];
256 
257     return D3D_OK;
258 }
259 
260 HRESULT NINE_WINAPI
NineTexture9_LockRect(struct NineTexture9 * This,UINT Level,D3DLOCKED_RECT * pLockedRect,const RECT * pRect,DWORD Flags)261 NineTexture9_LockRect( struct NineTexture9 *This,
262                        UINT Level,
263                        D3DLOCKED_RECT *pLockedRect,
264                        const RECT *pRect,
265                        DWORD Flags )
266 {
267     DBG("This=%p Level=%u pLockedRect=%p pRect=%p Flags=%d\n",
268         This, Level, pLockedRect, pRect, Flags);
269 
270     user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL);
271 
272     return NineSurface9_LockRect(This->surfaces[Level], pLockedRect,
273                                  pRect, Flags);
274 }
275 
276 HRESULT NINE_WINAPI
NineTexture9_UnlockRect(struct NineTexture9 * This,UINT Level)277 NineTexture9_UnlockRect( struct NineTexture9 *This,
278                          UINT Level )
279 {
280     DBG("This=%p Level=%u\n", This, Level);
281 
282     user_assert(Level < This->base.level_count, D3DERR_INVALIDCALL);
283 
284     return NineSurface9_UnlockRect(This->surfaces[Level]);
285 }
286 
287 HRESULT NINE_WINAPI
NineTexture9_AddDirtyRect(struct NineTexture9 * This,const RECT * pDirtyRect)288 NineTexture9_AddDirtyRect( struct NineTexture9 *This,
289                            const RECT *pDirtyRect )
290 {
291     DBG("This=%p pDirtyRect=%p[(%u,%u)-(%u,%u)]\n", This, pDirtyRect,
292         pDirtyRect ? pDirtyRect->left : 0, pDirtyRect ? pDirtyRect->top : 0,
293         pDirtyRect ? pDirtyRect->right : 0, pDirtyRect ? pDirtyRect->bottom : 0);
294 
295     /* Tracking dirty regions on DEFAULT resources is pointless,
296      * because we always write to the final storage. Just marked it dirty in
297      * case we need to generate mip maps.
298      */
299     if (This->base.base.pool == D3DPOOL_DEFAULT) {
300         if (This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP) {
301             This->base.dirty_mip = true;
302             BASETEX_REGISTER_UPDATE(&This->base);
303         }
304         return D3D_OK;
305     }
306 
307     if (This->base.base.pool == D3DPOOL_MANAGED) {
308         This->base.managed.dirty = true;
309         BASETEX_REGISTER_UPDATE(&This->base);
310     }
311 
312     if (!pDirtyRect) {
313         u_box_origin_2d(This->base.base.info.width0,
314                         This->base.base.info.height0, &This->dirty_rect);
315     } else {
316         if (This->dirty_rect.width == 0) {
317             rect_to_pipe_box_clamp(&This->dirty_rect, pDirtyRect);
318         } else {
319             struct pipe_box box;
320             rect_to_pipe_box_clamp(&box, pDirtyRect);
321             u_box_union_2d(&This->dirty_rect, &This->dirty_rect, &box);
322         }
323         (void) u_box_clip_2d(&This->dirty_rect, &This->dirty_rect,
324                              This->base.base.info.width0,
325                              This->base.base.info.height0);
326     }
327     return D3D_OK;
328 }
329 
330 IDirect3DTexture9Vtbl NineTexture9_vtable = {
331     (void *)NineUnknown_QueryInterface,
332     (void *)NineUnknown_AddRef,
333     (void *)NineUnknown_Release,
334     (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */
335     (void *)NineUnknown_SetPrivateData,
336     (void *)NineUnknown_GetPrivateData,
337     (void *)NineUnknown_FreePrivateData,
338     (void *)NineResource9_SetPriority,
339     (void *)NineResource9_GetPriority,
340     (void *)NineBaseTexture9_PreLoad,
341     (void *)NineResource9_GetType,
342     (void *)NineBaseTexture9_SetLOD,
343     (void *)NineBaseTexture9_GetLOD,
344     (void *)NineBaseTexture9_GetLevelCount,
345     (void *)NineBaseTexture9_SetAutoGenFilterType,
346     (void *)NineBaseTexture9_GetAutoGenFilterType,
347     (void *)NineBaseTexture9_GenerateMipSubLevels,
348     (void *)NineTexture9_GetLevelDesc,
349     (void *)NineTexture9_GetSurfaceLevel,
350     (void *)NineTexture9_LockRect,
351     (void *)NineTexture9_UnlockRect,
352     (void *)NineTexture9_AddDirtyRect
353 };
354 
355 static const GUID *NineTexture9_IIDs[] = {
356     &IID_IDirect3DTexture9,
357     &IID_IDirect3DBaseTexture9,
358     &IID_IDirect3DResource9,
359     &IID_IUnknown,
360     NULL
361 };
362 
363 HRESULT
NineTexture9_new(struct NineDevice9 * pDevice,UINT Width,UINT Height,UINT Levels,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,struct NineTexture9 ** ppOut,HANDLE * pSharedHandle)364 NineTexture9_new( struct NineDevice9 *pDevice,
365                   UINT Width, UINT Height, UINT Levels,
366                   DWORD Usage,
367                   D3DFORMAT Format,
368                   D3DPOOL Pool,
369                   struct NineTexture9 **ppOut,
370                   HANDLE *pSharedHandle )
371 {
372     NINE_DEVICE_CHILD_NEW(Texture9, ppOut, pDevice,
373                           Width, Height, Levels,
374                           Usage, Format, Pool, pSharedHandle);
375 }
376