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