1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2014 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 #include "nvkms-utils-flip.h"
25 #include "nvkms-private.h"
26 #include "nvkms-surface.h"
27 #include "nvkms-cursor.h"
28 #include "nvkms-sync.h"
29 
30 /*!
31  * Assign the elements in an NVSurfaceEvoPtr[NVKMS_MAX_EYES] array.
32  *
33  * Use NVEvoApiHandlesRec to translate an
34  * NvKmsSurfaceHandle[NVKMS_MAX_EYES] array into an an
35  * NVSurfaceEvoPtr[NVKMS_MAX_EYES] array.
36  *
37  * \param[in]  pOpenDevSurfaceHandles  The client's surfaces.
38  * \param[in]  surfaceHandles          The handles naming surfaces.
39  * \param[out] pSurfaceEvos            The surface pointers.
40  *
41  * \return  Return TRUE if all surfaceHandles could be successfully
42  *          translated into pSurfaceEvos.  Otherwise, return FALSE.
43  */
nvAssignSurfaceArray(const NVDevEvoRec * pDevEvo,const NVEvoApiHandlesRec * pOpenDevSurfaceHandles,const NvKmsSurfaceHandle surfaceHandles[NVKMS_MAX_EYES],const NvBool isUsedByCursorChannel,const NvBool isUsedByLayerChannel,NVSurfaceEvoPtr pSurfaceEvos[NVKMS_MAX_EYES])44 NvBool nvAssignSurfaceArray(
45     const NVDevEvoRec *pDevEvo,
46     const NVEvoApiHandlesRec *pOpenDevSurfaceHandles,
47     const NvKmsSurfaceHandle surfaceHandles[NVKMS_MAX_EYES],
48     const NvBool isUsedByCursorChannel,
49     const NvBool isUsedByLayerChannel,
50     NVSurfaceEvoPtr pSurfaceEvos[NVKMS_MAX_EYES])
51 {
52     NvU32 eye;
53 
54     nvkms_memset(pSurfaceEvos, 0, sizeof(NVSurfaceEvoRec *) * NVKMS_MAX_EYES);
55 
56     for (eye = 0; eye < NVKMS_MAX_EYES; eye++) {
57         if (surfaceHandles[eye] != 0) {
58             pSurfaceEvos[eye] =
59                 nvEvoGetSurfaceFromHandle(pDevEvo,
60                                           pOpenDevSurfaceHandles,
61                                           surfaceHandles[eye],
62                                           isUsedByCursorChannel,
63                                           isUsedByLayerChannel);
64             if ((pSurfaceEvos[eye] == NULL) ||
65                 (pSurfaceEvos[eye]->isoType != NVKMS_MEMORY_ISO)) {
66                 return FALSE;
67             }
68         }
69     }
70     return TRUE;
71 }
72 
73 
74 /*!
75  * Assign the NVFlipNIsoSurfaceEvoHwState.
76  *
77  * Use the given NvKmsNIsoSurface to populate the
78  * NVFlipNIsoSurfaceEvoHwState.  Validate that NvKmsNIsoSurface
79  * description is legitimate.
80  *
81  * \param[in]  pDevEvo        The device where the surface will be used.
82  * \param[in]  pOpenDevSurfaceHandles  The client's surfaces.
83  * \param[in]  pParamsNIso    The client's description of the NISO surface.
84  * \param[in]  notifier       Whether the NISO surface is a notifier.
85  * \param[in]  pChannel       The channel where the surface will be used.
86  * \param[out] pNIsoState     The NVKMS presentation of the NISO surface.
87  *
88  * \return  Return TRUE if the NVFlipNIsoSurfaceEvoHwState could be
89  *          assigned and validated.  Otherwise, return FALSE and leave
90  *          the NVFlipNIsoSurfaceEvoHwState untouched.
91  */
nvAssignNIsoEvoHwState(const NVDevEvoRec * pDevEvo,const NVEvoApiHandlesRec * pOpenDevSurfaceHandles,const struct NvKmsNIsoSurface * pParamsNIso,const NvBool notifier,const NvU32 layer,NVFlipNIsoSurfaceEvoHwState * pNIsoState)92 NvBool nvAssignNIsoEvoHwState(
93     const NVDevEvoRec *pDevEvo,
94     const NVEvoApiHandlesRec *pOpenDevSurfaceHandles,
95     const struct NvKmsNIsoSurface *pParamsNIso,
96     const NvBool notifier, /* TRUE=notifier; FALSE=semaphore */
97     const NvU32 layer,
98     NVFlipNIsoSurfaceEvoHwState *pNIsoState)
99 {
100     NVSurfaceEvoPtr pSurfaceEvo;
101     NvU32 elementSizeInBytes = 0, offsetInBytes, maxBytes;
102 
103     nvAssert(pParamsNIso->surfaceHandle != 0);
104 
105     pSurfaceEvo =
106         nvEvoGetSurfaceFromHandle(pDevEvo,
107                                   pOpenDevSurfaceHandles,
108                                   pParamsNIso->surfaceHandle,
109                                   FALSE /* isUsedByCursorChannel */,
110                                   TRUE /* isUsedByLayerChannel */);
111     if (pSurfaceEvo == NULL) {
112         return FALSE;
113     }
114 
115     /* Attempt to validate the surface: */
116 
117     /* Only pitch surfaces can be used */
118     if (pSurfaceEvo->layout != NvKmsSurfaceMemoryLayoutPitch) {
119         return FALSE;
120     }
121 
122     if (pSurfaceEvo->isoType != NVKMS_MEMORY_NISO) {
123         return FALSE;
124     }
125 
126     if ((pParamsNIso->format != NVKMS_NISO_FORMAT_FOUR_WORD) &&
127         (pParamsNIso->format != NVKMS_NISO_FORMAT_FOUR_WORD_NVDISPLAY) &&
128         (pParamsNIso->format != NVKMS_NISO_FORMAT_LEGACY)) {
129         return FALSE;
130     }
131 
132     if ((pDevEvo->caps.validNIsoFormatMask &
133          (1 << pParamsNIso->format)) == 0) {
134         return FALSE;
135     }
136 
137     /* Check that the item fits within the surface. */
138     switch (pParamsNIso->format) {
139     case NVKMS_NISO_FORMAT_FOUR_WORD:
140     case NVKMS_NISO_FORMAT_FOUR_WORD_NVDISPLAY:
141         elementSizeInBytes = 16;
142         break;
143     case NVKMS_NISO_FORMAT_LEGACY:
144         if (notifier) {
145             /* Legacy notifier size depends on the layer. */
146             elementSizeInBytes =
147                 pDevEvo->caps.legacyNotifierFormatSizeBytes[layer];
148         } else {
149             /* Legacy semaphores are always 4 bytes. */
150             elementSizeInBytes = 4;
151         }
152         break;
153     }
154 
155 #if defined(DEBUG)
156     /* Assert that the size calculated by nvkms-sync library is the same as the
157      * one we derived from channel caps above. */
158     if (notifier) {
159         NvBool overlay = (layer != NVKMS_MAIN_LAYER);
160         NvU32 libSize = nvKmsSizeOfNotifier(pParamsNIso->format, overlay);
161         nvAssert(libSize == elementSizeInBytes);
162     } else {
163         nvAssert(nvKmsSizeOfSemaphore(pParamsNIso->format) == elementSizeInBytes);
164     }
165 #endif
166     /*
167      * offsetInWords is an NvU16 and offsetInBytes is an NvU32, so
168      * neither of the expressions:
169      *   offsetInWords * 4
170      *   offsetInBytes + elementSizeInBytes
171      * should ever overflow.
172      */
173 
174     ct_assert(sizeof(pParamsNIso->offsetInWords) == 2);
175 
176     offsetInBytes = ((NvU32)pParamsNIso->offsetInWords) * 4;
177 
178     /*
179      * Compute the upper extent of the NISO element within the surface.
180      */
181 
182     maxBytes = offsetInBytes + elementSizeInBytes;
183 
184     if (maxBytes > pSurfaceEvo->planes[0].rmObjectSizeInBytes) {
185         return FALSE;
186     }
187 
188     /* EVO expects the NISO element to fit within a 4k page. */
189 
190     if (maxBytes > 4096) {
191         return FALSE;
192     }
193 
194     /*
195      * XXX NVKMS TODO: Check that the surface is in vidmem if
196      * NV5070_CTRL_SYSTEM_CAPS_BUG_644815_DNISO_VIDMEM_ONLY
197      */
198 
199     pNIsoState->pSurfaceEvo = pSurfaceEvo;
200     pNIsoState->format = pParamsNIso->format;
201     pNIsoState->offsetInWords = pParamsNIso->offsetInWords;
202 
203     return TRUE;
204 }
205 
nvAssignCompletionNotifierEvoHwState(const NVDevEvoRec * pDevEvo,const NVEvoApiHandlesRec * pOpenDevSurfaceHandles,const struct NvKmsCompletionNotifierDescription * pParamsNotif,const NvU32 layer,NVFlipCompletionNotifierEvoHwState * pNotif)206 NvBool nvAssignCompletionNotifierEvoHwState(
207     const NVDevEvoRec *pDevEvo,
208     const NVEvoApiHandlesRec *pOpenDevSurfaceHandles,
209     const struct NvKmsCompletionNotifierDescription *pParamsNotif,
210     const NvU32 layer,
211     NVFlipCompletionNotifierEvoHwState *pNotif)
212 {
213     NvBool ret;
214 
215     nvkms_memset(pNotif, 0, sizeof(*pNotif));
216 
217     /* If no surface is specified, we should not use a notifier. */
218     if (pParamsNotif->surface.surfaceHandle == 0) {
219         return TRUE;
220     }
221 
222     ret = nvAssignNIsoEvoHwState(pDevEvo,
223                                  pOpenDevSurfaceHandles,
224                                  &pParamsNotif->surface,
225                                  TRUE, /* notifier */
226                                  layer,
227                                  &pNotif->surface);
228     if (ret) {
229         pNotif->awaken = pParamsNotif->awaken;
230     }
231 
232     return ret;
233 }
234 
nvAssignSemaphoreEvoHwState(const NVDevEvoRec * pDevEvo,const NVEvoApiHandlesRec * pOpenDevSurfaceHandles,const NvU32 layer,const NvU32 sd,const struct NvKmsChannelSyncObjects * pChannelSyncObjects,NVFlipSyncObjectEvoHwState * pFlipSyncObject)235 NvBool nvAssignSemaphoreEvoHwState(
236     const NVDevEvoRec *pDevEvo,
237     const NVEvoApiHandlesRec *pOpenDevSurfaceHandles,
238     const NvU32 layer,
239     const NvU32 sd,
240     const struct NvKmsChannelSyncObjects *pChannelSyncObjects,
241     NVFlipSyncObjectEvoHwState *pFlipSyncObject)
242 {
243     NvBool ret;
244 
245     nvAssert(!pChannelSyncObjects->useSyncpt);
246 
247     nvkms_memset(pFlipSyncObject, 0, sizeof(*pFlipSyncObject));
248 
249     if (!pDevEvo->hal->caps.supportsIndependentAcqRelSemaphore) {
250         /*! acquire and release sema surface needs to be same */
251         if (pChannelSyncObjects->u.semaphores.acquire.surface.surfaceHandle !=
252             pChannelSyncObjects->u.semaphores.release.surface.surfaceHandle) {
253             return FALSE;
254         }
255         if (pChannelSyncObjects->u.semaphores.acquire.surface.format !=
256             pChannelSyncObjects->u.semaphores.release.surface.format) {
257             return FALSE;
258         }
259         if (pChannelSyncObjects->u.semaphores.acquire.surface.offsetInWords !=
260             pChannelSyncObjects->u.semaphores.release.surface.offsetInWords) {
261             return FALSE;
262         }
263     }
264 
265     /*! If no surface is specified, we should not use a semaphore.*/
266     if (pChannelSyncObjects->u.semaphores.acquire.surface.surfaceHandle != 0) {
267 
268         ret = nvAssignNIsoEvoHwState(
269                     pDevEvo,
270                     pOpenDevSurfaceHandles,
271                     &pChannelSyncObjects->u.semaphores.acquire.surface,
272                     FALSE, /* notifier */
273                     layer,
274                     &pFlipSyncObject->u.semaphores.acquireSurface);
275         if (ret) {
276             pFlipSyncObject->u.semaphores.acquireValue =
277                 pChannelSyncObjects->u.semaphores.acquire.value;
278         } else {
279             return ret;
280         }
281     }
282 
283     /*! If no surface is specified, we should not use a semaphore.*/
284     if (pChannelSyncObjects->u.semaphores.release.surface.surfaceHandle != 0) {
285 
286         ret = nvAssignNIsoEvoHwState(
287                     pDevEvo,
288                     pOpenDevSurfaceHandles,
289                     &pChannelSyncObjects->u.semaphores.release.surface,
290                     FALSE, /* notifier */
291                     layer,
292                     &pFlipSyncObject->u.semaphores.releaseSurface);
293         if (ret) {
294             pFlipSyncObject->u.semaphores.releaseValue =
295                 pChannelSyncObjects->u.semaphores.release.value;
296         } else {
297             return ret;
298         }
299     }
300 
301     return TRUE;
302 }
303 
nvValidatePerLayerCompParams(const struct NvKmsCompositionParams * pCompParams,const struct NvKmsCompositionCapabilities * pCaps,NVSurfaceEvoPtr pSurfaceEvo)304 NvBool nvValidatePerLayerCompParams(
305     const struct NvKmsCompositionParams *pCompParams,
306     const struct NvKmsCompositionCapabilities *pCaps,
307     NVSurfaceEvoPtr pSurfaceEvo)
308 {
309     const NvKmsSurfaceMemoryFormatInfo *pFormatInfo = (pSurfaceEvo != NULL) ?
310         nvKmsGetSurfaceMemoryFormatInfo(pSurfaceEvo->format) : NULL;
311     const enum NvKmsCompositionColorKeySelect colorKeySelect =
312         pCompParams->colorKeySelect;
313     NvU32 match;
314 
315     if ((pCaps->supportedColorKeySelects & NVBIT(colorKeySelect)) == 0x0) {
316         return FALSE;
317     }
318 
319     NVKMS_COMPOSITION_FOR_MATCH_BITS(colorKeySelect, match) {
320         if ((pCaps->colorKeySelect[colorKeySelect].supportedBlendModes[match] &
321                 NVBIT(pCompParams->blendingMode[match])) == 0x0) {
322             return FALSE;
323         }
324 
325         switch (pCompParams->blendingMode[match]) {
326         case NVKMS_COMPOSITION_BLENDING_MODE_NON_PREMULT_ALPHA:
327         case NVKMS_COMPOSITION_BLENDING_MODE_PREMULT_ALPHA:
328             if (pCompParams->surfaceAlpha != 0) {
329                 return FALSE;
330             }
331             break;
332         default:
333             break;
334         }
335     }
336 
337     /* Match and nomatch pixels should not use alpha blending mode at once. */
338     if ((colorKeySelect != NVKMS_COMPOSITION_COLOR_KEY_SELECT_DISABLE) &&
339         (NvKmsIsCompositionModeUseAlpha(pCompParams->blendingMode[0])) &&
340         (NvKmsIsCompositionModeUseAlpha(pCompParams->blendingMode[1]))) {
341        return FALSE;
342    }
343 
344     /*
345      * If surface is NULL, no further validation required. The composition
346      * parameters do not take effect if surface is NULL.
347      */
348     if (pFormatInfo == NULL || pFormatInfo->isYUV) {
349         return TRUE;
350     }
351 
352     /* Disable color keying for 8 Bpp surfaces. */
353     if ((colorKeySelect == NVKMS_COMPOSITION_COLOR_KEY_SELECT_SRC) ||
354         (colorKeySelect == NVKMS_COMPOSITION_COLOR_KEY_SELECT_DST)) {
355 
356         if (pFormatInfo->rgb.bytesPerPixel > 4) {
357             return FALSE;
358         }
359     }
360 
361     return TRUE;
362 }
363 
364 NvBool
nvAssignCursorSurface(const struct NvKmsPerOpenDev * pOpenDev,const NVDevEvoRec * pDevEvo,const struct NvKmsSetCursorImageCommonParams * pImgParams,NVSurfaceEvoPtr * pSurfaceEvo)365 nvAssignCursorSurface(const struct NvKmsPerOpenDev *pOpenDev,
366                       const NVDevEvoRec *pDevEvo,
367                       const struct NvKmsSetCursorImageCommonParams *pImgParams,
368                       NVSurfaceEvoPtr *pSurfaceEvo)
369 
370 {
371     const NVEvoApiHandlesRec *pOpenDevSurfaceHandles =
372         nvGetSurfaceHandlesFromOpenDevConst(pOpenDev);
373     NVSurfaceEvoPtr pSurfaceEvos[NVKMS_MAX_EYES] = { };
374 
375     if (!nvGetCursorImageSurfaces(pDevEvo,
376                                   pOpenDevSurfaceHandles,
377                                   pImgParams,
378                                   pSurfaceEvos)) {
379         return FALSE;
380     }
381 
382     /* XXX NVKMS TODO: add support for stereo cursor */
383     if (pSurfaceEvos[NVKMS_RIGHT] != NULL) {
384         return FALSE;
385     }
386 
387     if (pSurfaceEvos[NVKMS_LEFT] != NULL) {
388         if (!nvValidatePerLayerCompParams(&pImgParams->cursorCompParams,
389                                           &pDevEvo->caps.cursorCompositionCaps,
390                                           pSurfaceEvos[NVKMS_LEFT])) {
391             return FALSE;
392         }
393     }
394 
395     *pSurfaceEvo = pSurfaceEvos[NVKMS_LEFT];
396 
397     return TRUE;
398 }
399 
400