1/****************************************************************************
2 * Copyright (C) 2016 Intel Corporation.   All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * 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 DEALINGS
21 * IN THE SOFTWARE.
22 ***************************************************************************/
23
24#include "swr_context.h"
25#include "swr_fence.h"
26
27#include "util/u_inlines.h"
28#include "util/u_memory.h"
29
30/*
31 * Called by swr_fence_cb to complete the work queue
32 */
33void
34swr_fence_do_work(struct swr_fence *fence)
35{
36   struct swr_fence_work *work, *tmp;
37
38   if (fence->work.head.next) {
39      work = fence->work.head.next;
40      /* Immediately clear the head so any new work gets added to a new work
41       * queue */
42      p_atomic_set(&fence->work.head.next, 0);
43      p_atomic_set(&fence->work.tail, &fence->work.head);
44      p_atomic_set(&fence->work.count, 0);
45
46      do {
47         tmp = work->next;
48         work->callback(work);
49         FREE(work);
50         work = tmp;
51      } while(work);
52   }
53}
54
55
56/*
57 * Called by one of the specialized work routines below
58 */
59static inline void
60swr_add_fence_work(struct pipe_fence_handle *fh,
61                   struct swr_fence_work *work)
62{
63   /* If no fence, just do the work now */
64   if (!fh) {
65      work->callback(work);
66      FREE(work);
67      return;
68   }
69
70   struct swr_fence *fence  = swr_fence(fh);
71   p_atomic_set(&fence->work.tail->next, work);
72   p_atomic_set(&fence->work.tail, work);
73   p_atomic_inc(&fence->work.count);
74}
75
76
77/*
78 * Generic free/free_aligned, and delete vs/fs
79 */
80template<bool aligned_free>
81static void
82swr_free_cb(struct swr_fence_work *work)
83{
84   if (aligned_free)
85      AlignedFree(work->free.data);
86   else
87      FREE(work->free.data);
88}
89
90static void
91swr_delete_vs_cb(struct swr_fence_work *work)
92{
93   delete work->free.swr_vs;
94}
95
96static void
97swr_delete_fs_cb(struct swr_fence_work *work)
98{
99   delete work->free.swr_fs;
100}
101
102static void
103swr_delete_gs_cb(struct swr_fence_work *work)
104{
105   delete work->free.swr_gs;
106}
107
108static void
109swr_delete_tcs_cb(struct swr_fence_work *work)
110{
111   delete work->free.swr_tcs;
112}
113
114static void
115swr_delete_tes_cb(struct swr_fence_work *work)
116{
117   delete work->free.swr_tes;
118}
119
120
121bool
122swr_fence_work_free(struct pipe_fence_handle *fence, void *data,
123                    bool aligned_free)
124{
125   struct swr_fence_work *work = CALLOC_STRUCT(swr_fence_work);
126   if (!work)
127      return false;
128   if (aligned_free)
129      work->callback = swr_free_cb<true>;
130   else
131      work->callback = swr_free_cb<false>;
132   work->free.data = data;
133
134   swr_add_fence_work(fence, work);
135
136   return true;
137}
138
139bool
140swr_fence_work_delete_vs(struct pipe_fence_handle *fence,
141                         struct swr_vertex_shader *swr_vs)
142{
143   struct swr_fence_work *work = CALLOC_STRUCT(swr_fence_work);
144   if (!work)
145      return false;
146   work->callback = swr_delete_vs_cb;
147   work->free.swr_vs = swr_vs;
148
149   swr_add_fence_work(fence, work);
150
151   return true;
152}
153
154bool
155swr_fence_work_delete_fs(struct pipe_fence_handle *fence,
156                         struct swr_fragment_shader *swr_fs)
157{
158   struct swr_fence_work *work = CALLOC_STRUCT(swr_fence_work);
159   if (!work)
160      return false;
161   work->callback = swr_delete_fs_cb;
162   work->free.swr_fs = swr_fs;
163
164   swr_add_fence_work(fence, work);
165
166   return true;
167}
168
169bool
170swr_fence_work_delete_gs(struct pipe_fence_handle *fence,
171                         struct swr_geometry_shader *swr_gs)
172{
173   struct swr_fence_work *work = CALLOC_STRUCT(swr_fence_work);
174   if (!work)
175      return false;
176   work->callback = swr_delete_gs_cb;
177   work->free.swr_gs = swr_gs;
178
179   swr_add_fence_work(fence, work);
180
181   return true;
182}
183
184bool
185swr_fence_work_delete_tcs(struct pipe_fence_handle *fence,
186                          struct swr_tess_control_shader *swr_tcs)
187{
188   struct swr_fence_work *work = CALLOC_STRUCT(swr_fence_work);
189   if (!work)
190      return false;
191   work->callback = swr_delete_tcs_cb;
192   work->free.swr_tcs = swr_tcs;
193
194   swr_add_fence_work(fence, work);
195
196   return true;
197}
198
199
200bool
201swr_fence_work_delete_tes(struct pipe_fence_handle *fence,
202                          struct swr_tess_evaluation_shader *swr_tes)
203{
204   struct swr_fence_work *work = CALLOC_STRUCT(swr_fence_work);
205   if (!work)
206      return false;
207   work->callback = swr_delete_tes_cb;
208   work->free.swr_tes = swr_tes;
209
210   swr_add_fence_work(fence, work);
211
212   return true;
213}