1758b4ee8SAndy Ritger /*
2758b4ee8SAndy Ritger  * SPDX-FileCopyrightText: Copyright (c) 2017-2020 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3758b4ee8SAndy Ritger  * SPDX-License-Identifier: MIT
4758b4ee8SAndy Ritger  *
5758b4ee8SAndy Ritger  * Permission is hereby granted, free of charge, to any person obtaining a
6758b4ee8SAndy Ritger  * copy of this software and associated documentation files (the "Software"),
7758b4ee8SAndy Ritger  * to deal in the Software without restriction, including without limitation
8758b4ee8SAndy Ritger  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9758b4ee8SAndy Ritger  * and/or sell copies of the Software, and to permit persons to whom the
10758b4ee8SAndy Ritger  * Software is furnished to do so, subject to the following conditions:
11758b4ee8SAndy Ritger  *
12758b4ee8SAndy Ritger  * The above copyright notice and this permission notice shall be included in
13758b4ee8SAndy Ritger  * all copies or substantial portions of the Software.
14758b4ee8SAndy Ritger  *
15758b4ee8SAndy Ritger  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16758b4ee8SAndy Ritger  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17758b4ee8SAndy Ritger  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18758b4ee8SAndy Ritger  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19758b4ee8SAndy Ritger  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20758b4ee8SAndy Ritger  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21758b4ee8SAndy Ritger  * DEALINGS IN THE SOFTWARE.
22758b4ee8SAndy Ritger  */
23758b4ee8SAndy Ritger 
24758b4ee8SAndy Ritger #ifndef __NVKMS_HEADSURFACE_PRIV_H__
25758b4ee8SAndy Ritger #define __NVKMS_HEADSURFACE_PRIV_H__
26758b4ee8SAndy Ritger 
27758b4ee8SAndy Ritger #include "nvkms-types.h"
28758b4ee8SAndy Ritger #include "nvkms-headsurface.h"
29758b4ee8SAndy Ritger #include "nvkms-headsurface-config.h"
30758b4ee8SAndy Ritger #include "nvkms-surface.h"
31758b4ee8SAndy Ritger #include "nvkms-utils.h"
32758b4ee8SAndy Ritger 
33758b4ee8SAndy Ritger #include "nvidia-push-init.h"
34758b4ee8SAndy Ritger #include "nvidia-3d.h"
35758b4ee8SAndy Ritger 
36758b4ee8SAndy Ritger #include "nv_list.h"
37758b4ee8SAndy Ritger 
38758b4ee8SAndy Ritger /*
39758b4ee8SAndy Ritger  * This header file defines structures shared by the nvkms-headsurface*.c source
40758b4ee8SAndy Ritger  * files.  To the rest of nvkms, these structures should be opaque.
41758b4ee8SAndy Ritger  */
42758b4ee8SAndy Ritger 
43758b4ee8SAndy Ritger #define NVKMS_HEAD_SURFACE_MAX_NOTIFIERS_PER_HEAD 4
44758b4ee8SAndy Ritger #define NVKMS_HEAD_SURFACE_MAX_NOTIFIER_SIZE 16
45758b4ee8SAndy Ritger #define NVKMS_HEAD_SURFACE_NOTIFIER_BYTES_PER_HEAD \
46758b4ee8SAndy Ritger     (NVKMS_HEAD_SURFACE_MAX_NOTIFIERS_PER_HEAD *   \
47758b4ee8SAndy Ritger      NVKMS_HEAD_SURFACE_MAX_NOTIFIER_SIZE)
48758b4ee8SAndy Ritger 
49758b4ee8SAndy Ritger #define NVKMS_HEAD_SURFACE_MAX_FRAME_SEMAPHORES 2
50758b4ee8SAndy Ritger 
51758b4ee8SAndy Ritger #define NVKMS_HEAD_SURFACE_SEMAPHORE_BYTES_PER_HEAD \
52758b4ee8SAndy Ritger     (sizeof(NvGpuSemaphore) * NVKMS_HEAD_SURFACE_MAX_FRAME_SEMAPHORES)
53758b4ee8SAndy Ritger 
54758b4ee8SAndy Ritger #define NVKMS_HEAD_SURFACE_FRAME_SEMAPHORE_DISPLAYABLE    0xFFFFFFFF
55758b4ee8SAndy Ritger #define NVKMS_HEAD_SURFACE_FRAME_SEMAPHORE_RENDERABLE     0x11111111
56758b4ee8SAndy Ritger 
57758b4ee8SAndy Ritger /*
58758b4ee8SAndy Ritger  * XXX NVKMS HEADSURFACE TODO: HeadSurface uses both notifiers and semaphores
59758b4ee8SAndy Ritger  * for synchronization:
60758b4ee8SAndy Ritger  *
61758b4ee8SAndy Ritger  * - Notifiers to ensure the CPU waits until after the previous frame's flip
62758b4ee8SAndy Ritger  *   completes before starting the next frame.
63758b4ee8SAndy Ritger  *
64758b4ee8SAndy Ritger  * - Semaphores to ensure the flip to the next frame is not started until the
65758b4ee8SAndy Ritger  *   rendering for the next frame completes.
66758b4ee8SAndy Ritger  *
67758b4ee8SAndy Ritger  * We should simplify things by using semaphores for both.
68758b4ee8SAndy Ritger  */
69758b4ee8SAndy Ritger typedef struct _NVHsNotifiersOneSdRec {
70758b4ee8SAndy Ritger     NvU8 notifier
71758b4ee8SAndy Ritger         [NVKMS_MAX_HEADS_PER_DISP][NVKMS_HEAD_SURFACE_NOTIFIER_BYTES_PER_HEAD];
72758b4ee8SAndy Ritger     NvU8 semaphore
73758b4ee8SAndy Ritger         [NVKMS_MAX_HEADS_PER_DISP][NVKMS_HEAD_SURFACE_SEMAPHORE_BYTES_PER_HEAD];
74758b4ee8SAndy Ritger } NVHsNotifiersOneSdRec;
75758b4ee8SAndy Ritger 
76758b4ee8SAndy Ritger #define NVKMS_HEAD_SURFACE_NOTIFIERS_SIZE_IN_BYTES 4096
77758b4ee8SAndy Ritger 
78758b4ee8SAndy Ritger ct_assert(NVKMS_HEAD_SURFACE_NOTIFIERS_SIZE_IN_BYTES >=
79758b4ee8SAndy Ritger           sizeof(NVHsNotifiersOneSdRec));
80758b4ee8SAndy Ritger 
81758b4ee8SAndy Ritger typedef struct _NVHsNotifiersRec {
82758b4ee8SAndy Ritger 
83758b4ee8SAndy Ritger     NvU32 rmHandle;
84758b4ee8SAndy Ritger     NvKmsSurfaceHandle nvKmsHandle;
85758b4ee8SAndy Ritger     const NVSurfaceEvoRec *pSurfaceEvo;
86758b4ee8SAndy Ritger 
87758b4ee8SAndy Ritger     struct {
88758b4ee8SAndy Ritger         NVHsNotifiersOneSdRec *ptr;
89758b4ee8SAndy Ritger         struct {
90758b4ee8SAndy Ritger             NvU8 nextSlot;
91758b4ee8SAndy Ritger         } apiHead[NVKMS_MAX_HEADS_PER_DISP];
92758b4ee8SAndy Ritger     } sd[NVKMS_MAX_SUBDEVICES];
93758b4ee8SAndy Ritger 
94758b4ee8SAndy Ritger     enum NvKmsNIsoFormat nIsoFormat;
95758b4ee8SAndy Ritger 
96758b4ee8SAndy Ritger } NVHsNotifiersRec;
97758b4ee8SAndy Ritger 
98758b4ee8SAndy Ritger typedef struct _NVHsSurfaceRec {
99758b4ee8SAndy Ritger 
100758b4ee8SAndy Ritger     NvKmsSurfaceHandle nvKmsHandle;
101758b4ee8SAndy Ritger     NvU32 rmHandle;
102758b4ee8SAndy Ritger 
103758b4ee8SAndy Ritger     Nv3dBlockLinearLog2GobsPerBlock gobsPerBlock;
104758b4ee8SAndy Ritger 
105758b4ee8SAndy Ritger     const NVSurfaceEvoRec *pSurfaceEvo;
106758b4ee8SAndy Ritger 
107758b4ee8SAndy Ritger } NVHsSurfaceRec;
108758b4ee8SAndy Ritger 
109758b4ee8SAndy Ritger typedef struct _NVHsDeviceEvoRec {
110758b4ee8SAndy Ritger 
111758b4ee8SAndy Ritger     NVDevEvoRec *pDevEvo;
112758b4ee8SAndy Ritger 
113758b4ee8SAndy Ritger     NvU32 gpuVASpace;
114758b4ee8SAndy Ritger 
115758b4ee8SAndy Ritger     struct {
116758b4ee8SAndy Ritger         Nv3dDeviceRec device;
117758b4ee8SAndy Ritger     } nv3d;
118758b4ee8SAndy Ritger 
119758b4ee8SAndy Ritger     NVHsNotifiersRec notifiers;
120758b4ee8SAndy Ritger 
121758b4ee8SAndy Ritger } NVHsDeviceEvoRec;
122758b4ee8SAndy Ritger 
123758b4ee8SAndy Ritger enum NVHsChannelTexInfoEnum {
124758b4ee8SAndy Ritger     NVKMS_HEADSURFACE_TEXINFO_SRC     = 0,
125758b4ee8SAndy Ritger     /* XXX NVKMS HEADSURFACE TODO: enable all the below  */
126758b4ee8SAndy Ritger     NVKMS_HEADSURFACE_TEXINFO_CURSOR  = 1,
127758b4ee8SAndy Ritger     NVKMS_HEADSURFACE_TEXINFO_BLEND   = 2,
128758b4ee8SAndy Ritger     NVKMS_HEADSURFACE_TEXINFO_OFFSET  = 3,
129758b4ee8SAndy Ritger     NVKMS_HEADSURFACE_TEXINFO_OVERLAY = 4,
130758b4ee8SAndy Ritger     /* NVKMS_HEADSURFACE_TEXINFO_LUT     = 5, */
131758b4ee8SAndy Ritger     NVKMS_HEADSURFACE_TEXINFO_NUM,
132758b4ee8SAndy Ritger };
133758b4ee8SAndy Ritger 
134758b4ee8SAndy Ritger typedef struct _NVHsChannelStatisticsOneEyeRec {
135758b4ee8SAndy Ritger     /* Running total of the number of frames rendered by headSurface. */
136758b4ee8SAndy Ritger     NvU64 nFrames;
137758b4ee8SAndy Ritger 
138758b4ee8SAndy Ritger     /* Running total of the GPU time spent rendering, in nanoseconds. */
139758b4ee8SAndy Ritger     NvU64 gpuTimeSpent;
140758b4ee8SAndy Ritger 
141758b4ee8SAndy Ritger     /* We compute the FPS for 5 second periods. */
142758b4ee8SAndy Ritger     struct {
143758b4ee8SAndy Ritger         /*
144758b4ee8SAndy Ritger          * Running total of the number of frames rendered by headSurface; reset
145758b4ee8SAndy Ritger          * every 5 seconds.
146758b4ee8SAndy Ritger          */
147758b4ee8SAndy Ritger         NvU64 nFrames;
148758b4ee8SAndy Ritger         /*
149758b4ee8SAndy Ritger          * The time, in nanoseconds, when this FPS period started, so we know
150758b4ee8SAndy Ritger          * when the 5 second period is done.
151758b4ee8SAndy Ritger          */
152758b4ee8SAndy Ritger         NvU64 startTime;
153758b4ee8SAndy Ritger         /*
154758b4ee8SAndy Ritger          * Most recently computed FPS for the last 5 second period.
155758b4ee8SAndy Ritger          */
156758b4ee8SAndy Ritger         NvU64 framesPerMs;
157758b4ee8SAndy Ritger     } fps;
158758b4ee8SAndy Ritger } NVHsChannelStatisticsOneEyeRec;
159758b4ee8SAndy Ritger 
160758b4ee8SAndy Ritger typedef struct _NVHsChannelFlipQueueEntry {
161758b4ee8SAndy Ritger     NVListRec flipQueueEntry;
1624397463eSAndy Ritger     NVHsLayerRequestedFlipState hwState;
163758b4ee8SAndy Ritger } NVHsChannelFlipQueueEntry;
164758b4ee8SAndy Ritger 
165758b4ee8SAndy Ritger typedef struct _NVHsChannelEvoRec {
166758b4ee8SAndy Ritger 
167758b4ee8SAndy Ritger     NVDispEvoRec *pDispEvo;
168758b4ee8SAndy Ritger 
169758b4ee8SAndy Ritger     NvU32 apiHead;
170758b4ee8SAndy Ritger 
171758b4ee8SAndy Ritger     struct {
172758b4ee8SAndy Ritger         NvPushChannelRec channel;
173758b4ee8SAndy Ritger         NvU32 handlePool[NV_PUSH_CHANNEL_HANDLE_POOL_NUM];
174758b4ee8SAndy Ritger     } nvPush;
175758b4ee8SAndy Ritger 
176758b4ee8SAndy Ritger     struct {
177758b4ee8SAndy Ritger         NvU32 handle;
178758b4ee8SAndy Ritger         Nv3dChannelRec channel;
179758b4ee8SAndy Ritger         Nv3dRenderTexInfo texInfo[NVKMS_HEADSURFACE_TEXINFO_NUM];
180758b4ee8SAndy Ritger     } nv3d;
181758b4ee8SAndy Ritger 
182758b4ee8SAndy Ritger     struct {
183758b4ee8SAndy Ritger         NvU32 handle;
184758b4ee8SAndy Ritger     } nv2d;
185758b4ee8SAndy Ritger 
186758b4ee8SAndy Ritger     /*
1874397463eSAndy Ritger      * Flip request parameters are too large to declare on the stack.  We
1884397463eSAndy Ritger      * preallocate them here so that we don't have to allocate and free them on
1894397463eSAndy Ritger      * every headSurface flip.
190758b4ee8SAndy Ritger      */
1914397463eSAndy Ritger     struct NvKmsFlipRequestOneHead scratchParams;
192758b4ee8SAndy Ritger 
193758b4ee8SAndy Ritger     /*
194758b4ee8SAndy Ritger      * The index into NVDevEvoRec::apiHeadSurfaceAllDisps[apiHead]::surface[] to use
195758b4ee8SAndy Ritger      * for the next frame of headSurface.
196758b4ee8SAndy Ritger      */
197758b4ee8SAndy Ritger     NvU8 nextIndex;
198758b4ee8SAndy Ritger 
199758b4ee8SAndy Ritger     /*
200758b4ee8SAndy Ritger      * When neededForSwapGroup is true, frames of headSurface are rendered to
201758b4ee8SAndy Ritger      * alternating offsets within double-sized headSurface surfaces.  nextOffset
202758b4ee8SAndy Ritger      * is either 0 or 1, to select the offset of the next headSurface frame.
203758b4ee8SAndy Ritger      */
204758b4ee8SAndy Ritger     NvU8 nextOffset;
205758b4ee8SAndy Ritger 
206758b4ee8SAndy Ritger     /*
207758b4ee8SAndy Ritger      * HeadSurface flips are semaphore interlocked with headSurface rendering.
208758b4ee8SAndy Ritger      * We need to use a different semaphore offset for subsequent flips.
209758b4ee8SAndy Ritger      * frameSemaphoreIndex is used to alternate between
210758b4ee8SAndy Ritger      * NVKMS_HEAD_SURFACE_MAX_FRAME_SEMAPHORES offsets.
211758b4ee8SAndy Ritger      */
212758b4ee8SAndy Ritger     NvU8 frameSemaphoreIndex;
213758b4ee8SAndy Ritger 
214758b4ee8SAndy Ritger     NVHsChannelConfig config;
215758b4ee8SAndy Ritger 
216758b4ee8SAndy Ritger     NVVBlankCallbackPtr vBlankCallback;
217758b4ee8SAndy Ritger 
218758b4ee8SAndy Ritger     /*
219758b4ee8SAndy Ritger      * NVHsChannelEvoRec keeps a list of flip queue entries, and the "current"
220758b4ee8SAndy Ritger      * entry.  NVHsChannelFlipQueueEntry is a single entry in the flip queue.
221758b4ee8SAndy Ritger      *
222758b4ee8SAndy Ritger      * Each entry describes a validated flip request.  When NVKMS is called to
223758b4ee8SAndy Ritger      * build the next frame of headSurface, it inspects if the next entry in the
224758b4ee8SAndy Ritger      * queue is ready to flip (e.g., any semaphore acquires have been
225758b4ee8SAndy Ritger      * satisfied).  If the next flip queue entry is ready, we use it to replace
226758b4ee8SAndy Ritger      * the current entry.  Otherwise, we continue to use the existing current
227758b4ee8SAndy Ritger      * entry.
228758b4ee8SAndy Ritger      *
229758b4ee8SAndy Ritger      * Surfaces within an NVHsChannelFlipQueueEntry have their reference counts:
230758b4ee8SAndy Ritger      *
231758b4ee8SAndy Ritger      * - incremented when the NVHsChannelFlipQueueEntry is added to the flip
232758b4ee8SAndy Ritger      *   queue.
233758b4ee8SAndy Ritger      *
234758b4ee8SAndy Ritger      * - decremented when the NVHsChannelFlipQueueEntry is removed from current
235758b4ee8SAndy Ritger      *   (i.e., when we do the equivalent of "flip away").
236758b4ee8SAndy Ritger      *
237758b4ee8SAndy Ritger      * To simulate EVO/NVDisplay semaphore behavior, if an
238758b4ee8SAndy Ritger      * NVHsChannelFlipQueueEntry specifies a semaphore:
239758b4ee8SAndy Ritger      *
240758b4ee8SAndy Ritger      * - We wait for the semaphore's acquire value to be reached before
241758b4ee8SAndy Ritger      *   promoting the entry from the flip queue to current.
242758b4ee8SAndy Ritger      *
243758b4ee8SAndy Ritger      * - We write the semaphore's release value when the
244758b4ee8SAndy Ritger      *   NVHsChannelFlipQueueEntry is removed from current (i.e., when we do the
245758b4ee8SAndy Ritger      *   equivalent of "flip away").
246758b4ee8SAndy Ritger      */
247758b4ee8SAndy Ritger 
248758b4ee8SAndy Ritger     struct {
2494397463eSAndy Ritger         NVHsLayerRequestedFlipState current;
250758b4ee8SAndy Ritger         NVListRec queue;
251758b4ee8SAndy Ritger     } flipQueue[NVKMS_MAX_LAYERS_PER_HEAD];
252758b4ee8SAndy Ritger 
253758b4ee8SAndy Ritger     /*
254758b4ee8SAndy Ritger      * This cached main layer surface needed when the main layer transitioning
255758b4ee8SAndy Ritger      * out of headSurface due to exiting a swapgroup. I.e. in this path:
256758b4ee8SAndy Ritger      *     nvHsConfigStop() => HsConfigRestoreMainLayerSurface()
257758b4ee8SAndy Ritger      */
258758b4ee8SAndy Ritger     struct {
259758b4ee8SAndy Ritger         NVSurfaceEvoPtr pSurfaceEvo[NVKMS_MAX_EYES];
260758b4ee8SAndy Ritger     } flipQueueMainLayerState;
261758b4ee8SAndy Ritger 
262758b4ee8SAndy Ritger     NvU64 lastCallbackUSec;
263758b4ee8SAndy Ritger 
264758b4ee8SAndy Ritger     /*
265758b4ee8SAndy Ritger      * For NVKMS headsurface swap groups, at some point after the flip has been
266758b4ee8SAndy Ritger      * issued, NVKMS needs to check the notifier associated with that flip to
267758b4ee8SAndy Ritger      * see if the flip has been completed and release the deferred request
268758b4ee8SAndy Ritger      * fifo entry associated with that flip.  This bool reflects whether that
269758b4ee8SAndy Ritger      * check is done during the headsurface vblank interrupt callback or later
270758b4ee8SAndy Ritger      * during the RG line 1 interrupt callback.
271758b4ee8SAndy Ritger      */
272758b4ee8SAndy Ritger     NvBool usingRgIntrForSwapGroups;
273758b4ee8SAndy Ritger 
274758b4ee8SAndy Ritger     /*
2754397463eSAndy Ritger      * Pointer to the RG line interrupt callback object. This is needed to
276758b4ee8SAndy Ritger      * enabled and disable the RG interrupt callback.
277758b4ee8SAndy Ritger      */
2784397463eSAndy Ritger     NVRgLine1CallbackPtr pRgIntrCallback;
279758b4ee8SAndy Ritger 
280758b4ee8SAndy Ritger #if NVKMS_PROCFS_ENABLE
281758b4ee8SAndy Ritger 
282758b4ee8SAndy Ritger     /*
283758b4ee8SAndy Ritger      * We track statistics differently for SwapGroup and non-SwapGroup
284758b4ee8SAndy Ritger      * headSurface; abstract the grouping into "slots".  For non-SwapGroup there
285758b4ee8SAndy Ritger      * is only one rendered frame (one "slot").  For SwapGroup, there are three
286758b4ee8SAndy Ritger      * different rendered frames (so three "slots").
287758b4ee8SAndy Ritger      */
288758b4ee8SAndy Ritger #define NVKMS_HEADSURFACE_STATS_MAX_SLOTS 3
289758b4ee8SAndy Ritger 
290758b4ee8SAndy Ritger #define NVKMS_HEADSURFACE_STATS_SEMAPHORE_BEFORE 0
291758b4ee8SAndy Ritger #define NVKMS_HEADSURFACE_STATS_SEMAPHORE_AFTER  1
292758b4ee8SAndy Ritger 
293758b4ee8SAndy Ritger     /*
294758b4ee8SAndy Ritger      * One semaphore before the frame, and one semaphore after the frame.
295758b4ee8SAndy Ritger      */
296758b4ee8SAndy Ritger #define NVKMS_HEAD_SURFACE_STATS_SEMAPHORE_STAGE_COUNT 2
297758b4ee8SAndy Ritger 
298758b4ee8SAndy Ritger     /*
299758b4ee8SAndy Ritger      * We need semaphores for each stereo eye for each "slot".
300758b4ee8SAndy Ritger      */
301758b4ee8SAndy Ritger #define NVKMS_HEADSURFACE_STATS_MAX_SEMAPHORES        \
302758b4ee8SAndy Ritger     (NVKMS_HEAD_SURFACE_STATS_SEMAPHORE_STAGE_COUNT * \
303758b4ee8SAndy Ritger      NVKMS_MAX_EYES *                                 \
304758b4ee8SAndy Ritger      NVKMS_HEADSURFACE_STATS_MAX_SLOTS)
305758b4ee8SAndy Ritger 
306758b4ee8SAndy Ritger     struct {
307758b4ee8SAndy Ritger 
308758b4ee8SAndy Ritger         NVHsChannelStatisticsOneEyeRec
309758b4ee8SAndy Ritger             perEye[NVKMS_MAX_EYES][NVKMS_HEADSURFACE_STATS_MAX_SLOTS];
310758b4ee8SAndy Ritger 
311758b4ee8SAndy Ritger         /* How often we were called back before the previous frame was done. */
312758b4ee8SAndy Ritger         NvU64 nPreviousFrameNotDone;
313758b4ee8SAndy Ritger 
314758b4ee8SAndy Ritger         /* How often we did not update HS backbuffer with non-sg content. */
315758b4ee8SAndy Ritger         NvU64 nOmittedNonSgHsUpdates;
316758b4ee8SAndy Ritger 
317758b4ee8SAndy Ritger         /* How often did we have fullscreen swapgroup, and didn't. */
318758b4ee8SAndy Ritger         NvU64 nFullscreenSgFrames;
319758b4ee8SAndy Ritger         NvU64 nNonFullscreenSgFrames;
320758b4ee8SAndy Ritger 
321758b4ee8SAndy Ritger         /*
322758b4ee8SAndy Ritger          * Statistics on which Display Memory Interface (DMI) scanline we are on
323758b4ee8SAndy Ritger          * when headSurface is called.
324758b4ee8SAndy Ritger          *
325758b4ee8SAndy Ritger          * pHistogram is a dynamically allocated array of counts.  The array has
326758b4ee8SAndy Ritger          * vVisible + 1 elements (the +1 is because the hardware-reported
327758b4ee8SAndy Ritger          * scanline values are in the inclusive range [0,vVisible]).  Each
328758b4ee8SAndy Ritger          * element contains how many times we've been called back while on that
329758b4ee8SAndy Ritger          * scanline.
330758b4ee8SAndy Ritger          *
331758b4ee8SAndy Ritger          * When in the blanking region, there isn't a DMI scanline.  We
332758b4ee8SAndy Ritger          * increment n{,Not}InBlankingPeriod to keep track of how often we are
333758b4ee8SAndy Ritger          * called back while in the blanking region.
334758b4ee8SAndy Ritger          */
335758b4ee8SAndy Ritger         struct {
336758b4ee8SAndy Ritger             NvU64 *pHistogram; /* array with vVisible elements */
337758b4ee8SAndy Ritger             NvU16 vVisible;
338758b4ee8SAndy Ritger             NvU64 nInBlankingPeriod;
339758b4ee8SAndy Ritger             NvU64 nNotInBlankingPeriod;
340758b4ee8SAndy Ritger         } scanLine;
341758b4ee8SAndy Ritger 
342758b4ee8SAndy Ritger     } statistics;
343758b4ee8SAndy Ritger #else
344758b4ee8SAndy Ritger #define NVKMS_HEADSURFACE_STATS_MAX_SEMAPHORES 0
345758b4ee8SAndy Ritger #endif /* NVKMS_PROCFS_ENABLE */
346758b4ee8SAndy Ritger 
347758b4ee8SAndy Ritger     /*
348758b4ee8SAndy Ritger      * We need one semaphore for the non-stall interrupt following rendering to
349758b4ee8SAndy Ritger      * the next viewport offset with swapgroups enabled.
350758b4ee8SAndy Ritger      */
351758b4ee8SAndy Ritger #define NVKMS_HEADSURFACE_VIEWPORT_OFFSET_SEMAPHORE_INDEX \
352758b4ee8SAndy Ritger     NVKMS_HEADSURFACE_STATS_MAX_SEMAPHORES
353758b4ee8SAndy Ritger 
354758b4ee8SAndy Ritger #define NVKMS_HEADSURFACE_MAX_SEMAPHORES \
355758b4ee8SAndy Ritger     (NVKMS_HEADSURFACE_VIEWPORT_OFFSET_SEMAPHORE_INDEX + 1)
356758b4ee8SAndy Ritger 
357758b4ee8SAndy Ritger     /*
358758b4ee8SAndy Ritger      * Whether this channel has kicked off rendering to a new viewport offset
359758b4ee8SAndy Ritger      * for non-swapgroup content updates, but hasn't yet kicked off the
360758b4ee8SAndy Ritger      * viewport flip to the new offset.  Used to prevent rendering a new
361758b4ee8SAndy Ritger      * frame if rendering the previous frame took longer than a full frame of
362758b4ee8SAndy Ritger      * scanout.
363758b4ee8SAndy Ritger      */
364758b4ee8SAndy Ritger     NvBool viewportFlipPending;
365758b4ee8SAndy Ritger 
366758b4ee8SAndy Ritger     /*
367758b4ee8SAndy Ritger      * Recorded timestamp of the last headsurface flip. Used for deciding if
368758b4ee8SAndy Ritger      * certain blits to the headsurface can be omitted.
369758b4ee8SAndy Ritger      */
370758b4ee8SAndy Ritger     NvU64 lastHsClientFlipTimeUs;
371758b4ee8SAndy Ritger 
372758b4ee8SAndy Ritger     /*
373758b4ee8SAndy Ritger      * If this channel has kicked off a real flip while swapgroups were active,
374758b4ee8SAndy Ritger      * mark this channel as using real flips instead of blits for swapgroups,
375758b4ee8SAndy Ritger      * don't fast forward through headsurface flips (since every flip needs to
376758b4ee8SAndy Ritger      * be kicked off with every swapgroup ready event), and skip the part of
377758b4ee8SAndy Ritger      * the RG interrupt that would update non-swapgroup content.
378758b4ee8SAndy Ritger      */
379758b4ee8SAndy Ritger     NvBool swapGroupFlipping;
380758b4ee8SAndy Ritger 
381758b4ee8SAndy Ritger } NVHsChannelEvoRec;
382758b4ee8SAndy Ritger 
Hs3dStatisticsGetSlot(const NVHsChannelEvoRec * pHsChannel,const NvHsNextFrameRequestType requestType,const NvU8 dstBufferIndex,const NvBool honorSwapGroupClipList)383758b4ee8SAndy Ritger static inline NvU8 Hs3dStatisticsGetSlot(
384758b4ee8SAndy Ritger     const NVHsChannelEvoRec *pHsChannel,
385758b4ee8SAndy Ritger     const NvHsNextFrameRequestType requestType,
386758b4ee8SAndy Ritger     const NvU8 dstBufferIndex,
387758b4ee8SAndy Ritger     const NvBool honorSwapGroupClipList)
388758b4ee8SAndy Ritger {
389758b4ee8SAndy Ritger     if (pHsChannel->config.neededForSwapGroup) {
390758b4ee8SAndy Ritger         switch (requestType) {
391758b4ee8SAndy Ritger         case NV_HS_NEXT_FRAME_REQUEST_TYPE_FIRST_FRAME:
392758b4ee8SAndy Ritger             /*
393758b4ee8SAndy Ritger              * SwapGroup FIRST_FRAME will render to pHsChannel->nextIndex with
394758b4ee8SAndy Ritger              * honorSwapGroupClipList==false.
395758b4ee8SAndy Ritger              */
396758b4ee8SAndy Ritger             nvAssert(dstBufferIndex < 2);
397758b4ee8SAndy Ritger             return dstBufferIndex;
398758b4ee8SAndy Ritger         case NV_HS_NEXT_FRAME_REQUEST_TYPE_VBLANK:
399758b4ee8SAndy Ritger             /*
400758b4ee8SAndy Ritger              * SwapGroup VBLANK fully populates the nextIndex buffer
401758b4ee8SAndy Ritger              * (honorSwapGroupClipList==false), and only populates the
402758b4ee8SAndy Ritger              * non-swapgroup regions of the current index.
403758b4ee8SAndy Ritger              */
404758b4ee8SAndy Ritger             return honorSwapGroupClipList ? 0 : 1;
405758b4ee8SAndy Ritger         case NV_HS_NEXT_FRAME_REQUEST_TYPE_SWAP_GROUP_READY:
406758b4ee8SAndy Ritger             return 2;
407758b4ee8SAndy Ritger         }
408758b4ee8SAndy Ritger     }
409758b4ee8SAndy Ritger 
410758b4ee8SAndy Ritger     return 0; /* non-SwapGroup always only uses slot 0 */
411758b4ee8SAndy Ritger }
412758b4ee8SAndy Ritger 
413758b4ee8SAndy Ritger /*!
414758b4ee8SAndy Ritger  * Get the offset, in words, of the frame semaphore within NVHsNotifiersOneSdRec
415758b4ee8SAndy Ritger  * that corresponds to (head, frameSemaphoreIndex).
416758b4ee8SAndy Ritger  */
HsGetFrameSemaphoreOffsetInWords(const NVHsChannelEvoRec * pHsChannel)417758b4ee8SAndy Ritger static inline NvU16 HsGetFrameSemaphoreOffsetInWords(
418758b4ee8SAndy Ritger     const NVHsChannelEvoRec *pHsChannel)
419758b4ee8SAndy Ritger {
420758b4ee8SAndy Ritger     const NvU16 semBase =
421758b4ee8SAndy Ritger         offsetof(NVHsNotifiersOneSdRec, semaphore[pHsChannel->apiHead]);
422758b4ee8SAndy Ritger     const NvU16 semOffset = sizeof(NvGpuSemaphore) *
423758b4ee8SAndy Ritger         pHsChannel->frameSemaphoreIndex;
424758b4ee8SAndy Ritger 
425758b4ee8SAndy Ritger     const NvU16 offsetInBytes = semBase + semOffset;
426758b4ee8SAndy Ritger 
427758b4ee8SAndy Ritger     /*
428758b4ee8SAndy Ritger      * NVHsNotifiersOneSdRec::semaphore should be word-aligned, and
429758b4ee8SAndy Ritger      * sizeof(NvGpuSemaphore) is a multiple of words, so the offset to any
430758b4ee8SAndy Ritger      * NvGpuSemaphore within the array should be word-aligned.
431758b4ee8SAndy Ritger      */
432758b4ee8SAndy Ritger     nvAssert((offsetInBytes % 4) == 0);
433758b4ee8SAndy Ritger 
434758b4ee8SAndy Ritger     return offsetInBytes / 4;
435758b4ee8SAndy Ritger }
436758b4ee8SAndy Ritger 
HsIncrementFrameSemaphoreIndex(NVHsChannelEvoRec * pHsChannel)437758b4ee8SAndy Ritger static inline void HsIncrementFrameSemaphoreIndex(
438758b4ee8SAndy Ritger     NVHsChannelEvoRec *pHsChannel)
439758b4ee8SAndy Ritger {
440758b4ee8SAndy Ritger     pHsChannel->frameSemaphoreIndex++;
441758b4ee8SAndy Ritger     pHsChannel->frameSemaphoreIndex %= NVKMS_HEAD_SURFACE_MAX_FRAME_SEMAPHORES;
442758b4ee8SAndy Ritger }
443758b4ee8SAndy Ritger 
HsGetPreviousOffset(const NVHsChannelEvoRec * pHsChannel)444758b4ee8SAndy Ritger static inline NvU8 HsGetPreviousOffset(
445758b4ee8SAndy Ritger     const NVHsChannelEvoRec *pHsChannel)
446758b4ee8SAndy Ritger {
447758b4ee8SAndy Ritger     nvAssert(pHsChannel->config.neededForSwapGroup);
448758b4ee8SAndy Ritger 
449758b4ee8SAndy Ritger     nvAssert(pHsChannel->config.surfaceSize.height ==
450758b4ee8SAndy Ritger              (pHsChannel->config.frameSize.height * 2));
451758b4ee8SAndy Ritger 
452758b4ee8SAndy Ritger     return A_minus_b_with_wrap_U8(pHsChannel->nextOffset, 1,
453758b4ee8SAndy Ritger                                   NVKMS_HEAD_SURFACE_MAX_BUFFERS);
454758b4ee8SAndy Ritger }
455758b4ee8SAndy Ritger 
HsIncrementNextOffset(const NVHsDeviceEvoRec * pHsDevice,NVHsChannelEvoRec * pHsChannel)456758b4ee8SAndy Ritger static inline void HsIncrementNextOffset(
457758b4ee8SAndy Ritger     const NVHsDeviceEvoRec *pHsDevice,
458758b4ee8SAndy Ritger     NVHsChannelEvoRec *pHsChannel)
459758b4ee8SAndy Ritger {
460758b4ee8SAndy Ritger     nvAssert(pHsChannel->config.neededForSwapGroup);
461758b4ee8SAndy Ritger 
462758b4ee8SAndy Ritger     nvAssert(pHsChannel->config.surfaceSize.height ==
463758b4ee8SAndy Ritger              (pHsChannel->config.frameSize.height * 2));
464758b4ee8SAndy Ritger 
465758b4ee8SAndy Ritger     pHsChannel->nextOffset++;
466758b4ee8SAndy Ritger     pHsChannel->nextOffset %= 2;
467758b4ee8SAndy Ritger }
468758b4ee8SAndy Ritger 
HsIncrementNextIndex(const NVHsDeviceEvoRec * pHsDevice,NVHsChannelEvoRec * pHsChannel)469758b4ee8SAndy Ritger static inline void HsIncrementNextIndex(
470758b4ee8SAndy Ritger     const NVHsDeviceEvoRec *pHsDevice,
471758b4ee8SAndy Ritger     NVHsChannelEvoRec *pHsChannel)
472758b4ee8SAndy Ritger {
473758b4ee8SAndy Ritger     const NVDevEvoRec *pDevEvo = pHsDevice->pDevEvo;
474758b4ee8SAndy Ritger     const NvU32 surfaceCount =
475758b4ee8SAndy Ritger         pDevEvo->apiHeadSurfaceAllDisps[pHsChannel->apiHead].surfaceCount;
476758b4ee8SAndy Ritger 
477758b4ee8SAndy Ritger     nvAssert(surfaceCount > 0);
478758b4ee8SAndy Ritger 
479758b4ee8SAndy Ritger     pHsChannel->nextIndex++;
480758b4ee8SAndy Ritger     pHsChannel->nextIndex %= surfaceCount;
481758b4ee8SAndy Ritger }
482758b4ee8SAndy Ritger 
HsChangeSurfaceFlipRefCount(NVDevEvoPtr pDevEvo,NVSurfaceEvoPtr pSurfaceEvo,NvBool increase)483758b4ee8SAndy Ritger static inline void HsChangeSurfaceFlipRefCount(
484*b5bf85a8SAndy Ritger     NVDevEvoPtr pDevEvo,
485758b4ee8SAndy Ritger     NVSurfaceEvoPtr pSurfaceEvo,
486758b4ee8SAndy Ritger     NvBool increase)
487758b4ee8SAndy Ritger {
488758b4ee8SAndy Ritger     if (pSurfaceEvo != NULL) {
489758b4ee8SAndy Ritger         if (increase) {
490758b4ee8SAndy Ritger             nvEvoIncrementSurfaceRefCnts(pSurfaceEvo);
491758b4ee8SAndy Ritger         } else {
492*b5bf85a8SAndy Ritger             nvEvoDecrementSurfaceRefCnts(pDevEvo, pSurfaceEvo);
493758b4ee8SAndy Ritger         }
494758b4ee8SAndy Ritger     }
495758b4ee8SAndy Ritger }
496758b4ee8SAndy Ritger 
497758b4ee8SAndy Ritger /*!
4984397463eSAndy Ritger  * Get the last NVHsLayerRequestedFlipState entry in the pHsChannel's flip queue for
499758b4ee8SAndy Ritger  * the specified layer.
500758b4ee8SAndy Ritger  *
501758b4ee8SAndy Ritger  * If the flip queue is empty, return the 'current' entry.  Otherwise, return
502758b4ee8SAndy Ritger  * the most recently queued entry.
503758b4ee8SAndy Ritger  *
504758b4ee8SAndy Ritger  * This function cannot fail.
505758b4ee8SAndy Ritger  */
HsGetLastFlipQueueEntry(const NVHsChannelEvoRec * pHsChannel,const NvU8 layer)5064397463eSAndy Ritger static inline const NVHsLayerRequestedFlipState *HsGetLastFlipQueueEntry(
507758b4ee8SAndy Ritger     const NVHsChannelEvoRec *pHsChannel,
508758b4ee8SAndy Ritger     const NvU8 layer)
509758b4ee8SAndy Ritger {
510758b4ee8SAndy Ritger     const NVListRec *pFlipQueue = &pHsChannel->flipQueue[layer].queue;
511758b4ee8SAndy Ritger     const NVHsChannelFlipQueueEntry *pEntry;
512758b4ee8SAndy Ritger 
513758b4ee8SAndy Ritger     /*
514758b4ee8SAndy Ritger      * XXX NVKMS HEADSURFACE TODO: use nvListIsEmpty() once bugfix_main is
515758b4ee8SAndy Ritger      * updated to make nvListIsEmpty()'s argument const; see changelist
516758b4ee8SAndy Ritger      * 23614050.
517758b4ee8SAndy Ritger      *
518758b4ee8SAndy Ritger      * if (nvListIsEmpty(pFlipQueue)) {
519758b4ee8SAndy Ritger      */
520758b4ee8SAndy Ritger     if (pFlipQueue->next == pFlipQueue) {
521758b4ee8SAndy Ritger         return &pHsChannel->flipQueue[layer].current;
522758b4ee8SAndy Ritger     }
523758b4ee8SAndy Ritger 
524758b4ee8SAndy Ritger     pEntry = nvListLastEntry(pFlipQueue,
525758b4ee8SAndy Ritger                              NVHsChannelFlipQueueEntry,
526758b4ee8SAndy Ritger                              flipQueueEntry);
527758b4ee8SAndy Ritger 
528758b4ee8SAndy Ritger     return &pEntry->hwState;
529758b4ee8SAndy Ritger }
530758b4ee8SAndy Ritger 
531758b4ee8SAndy Ritger #endif /* __NVKMS_HEADSURFACE_PRIV_H__ */
532