1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2023 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief CTS implementation of the NVIDIA BitstreamBuffer interface.
22 *//*--------------------------------------------------------------------*/
23 /*
24 * Copyright 2023 NVIDIA Corporation.
25 *
26 * Licensed under the Apache License, Version 2.0 (the "License");
27 * you may not use this file except in compliance with the License.
28 * You may obtain a copy of the License at
29 *
30 * http://www.apache.org/licenses/LICENSE-2.0
31 *
32 * Unless required by applicable law or agreed to in writing, software
33 * distributed under the License is distributed on an "AS IS" BASIS,
34 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
35 * See the License for the specific language governing permissions and
36 * limitations under the License.
37 */
38
39 #include "vktBitstreamBufferImpl.hpp"
40
41 #include <cstring>
42
43 namespace vkt
44 {
45 namespace video
46 {
47
48 VkResult
Create(DeviceContext* devctx, deUint32 queueFamilyIndex, VkDeviceSize bufferSize, VkDeviceSize bufferOffsetAlignment, VkDeviceSize bufferSizeAlignment, VkSharedBaseObj<BitstreamBufferImpl>& vulkanBitstreamBuffer, const VkVideoProfileListInfoKHR* profileList)49 BitstreamBufferImpl::Create(DeviceContext* devctx, deUint32 queueFamilyIndex, VkDeviceSize bufferSize, VkDeviceSize bufferOffsetAlignment, VkDeviceSize bufferSizeAlignment, VkSharedBaseObj<BitstreamBufferImpl>& vulkanBitstreamBuffer, const VkVideoProfileListInfoKHR* profileList)
50 {
51 VkSharedBaseObj<BitstreamBufferImpl> vkBitstreamBuffer(new BitstreamBufferImpl(devctx,
52 queueFamilyIndex,
53 bufferOffsetAlignment,
54 bufferSizeAlignment,
55 profileList));
56 DE_ASSERT(vkBitstreamBuffer);
57
58 VK_CHECK(vkBitstreamBuffer->Initialize(bufferSize));
59
60 vulkanBitstreamBuffer = vkBitstreamBuffer;
61
62 return VK_SUCCESS;
63 }
64
Initialize(VkDeviceSize bufferSize)65 VkResult BitstreamBufferImpl::Initialize(VkDeviceSize bufferSize)
66 {
67 auto& vk = m_devctx->getDeviceDriver();
68 auto device = m_devctx->device;
69
70 if (m_bufferSize >= bufferSize)
71 {
72 VkDeviceSize size = MemsetData(0x00, 0, m_bufferSize);
73 DE_ASSERT(size == m_bufferSize);
74 DE_UNREF(size);
75 return VK_SUCCESS;
76 }
77
78 VkBufferCreateInfo createBufferInfo = {};
79 createBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
80 createBufferInfo.pNext = m_profileList;
81 createBufferInfo.size = deAlignSize(bufferSize, m_bufferSizeAlignment);
82 createBufferInfo.usage = VK_BUFFER_USAGE_VIDEO_DECODE_SRC_BIT_KHR;
83 createBufferInfo.flags = 0;
84 createBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
85 createBufferInfo.queueFamilyIndexCount = 1;
86 createBufferInfo.pQueueFamilyIndices = &m_queueFamilyIndex;
87 m_bitstreamBuffer = BufferPtr(new BufferWithMemory(vk, device, m_devctx->allocator(), createBufferInfo, MemoryRequirement::HostVisible | MemoryRequirement::Coherent | MemoryRequirement::Cached));
88
89 m_bufferSize = bufferSize;
90
91 return VK_SUCCESS;
92 }
93
CopyDataToBuffer(const deUint8* pData, VkDeviceSize size, VkDeviceSize& dstBufferOffset) const94 VkResult BitstreamBufferImpl::CopyDataToBuffer(const deUint8* pData,
95 VkDeviceSize size,
96 VkDeviceSize& dstBufferOffset) const
97 {
98 DE_ASSERT((pData != nullptr) && (size > 0) && (size < 10 * 1024 * 1024)); // 10 MiB should be big enough for any CTS test.
99
100 dstBufferOffset = deAlignSize(dstBufferOffset, m_bufferOffsetAlignment);
101 DE_ASSERT((dstBufferOffset + size) <= m_bufferSize);
102
103 auto* bitstreamBasePtr = static_cast<deUint8*>(m_bitstreamBuffer->getAllocation().getHostPtr());
104 deMemcpy(bitstreamBasePtr + dstBufferOffset, pData, size);
105 vk::flushAlloc(m_devctx->getDeviceDriver(), m_devctx->device, m_bitstreamBuffer->getAllocation());
106
107 return VK_SUCCESS;
108 }
109
GetMaxSize() const110 VkDeviceSize BitstreamBufferImpl::GetMaxSize() const
111 {
112 return m_bufferSize;
113 }
114
GetOffsetAlignment() const115 VkDeviceSize BitstreamBufferImpl::GetOffsetAlignment() const
116 {
117 return m_bufferOffsetAlignment;
118 }
119
GetSizeAlignment() const120 VkDeviceSize BitstreamBufferImpl::GetSizeAlignment() const
121 {
122 // REVIEW: Cache this?
123 auto reqs = getBufferMemoryRequirements(m_devctx->getDeviceDriver(), m_devctx->device, m_bitstreamBuffer->get());
124 return reqs.alignment;
125 }
126
Resize(VkDeviceSize, VkDeviceSize, VkDeviceSize)127 VkDeviceSize BitstreamBufferImpl::Resize(VkDeviceSize, VkDeviceSize, VkDeviceSize)
128 {
129 TCU_THROW(InternalError, "Bitstream buffers should never need to be resized in the CTS");
130 }
131
Clone(VkDeviceSize, VkDeviceSize, VkDeviceSize, VkSharedBaseObj<VulkanBitstreamBuffer>&)132 VkDeviceSize BitstreamBufferImpl::Clone(VkDeviceSize, VkDeviceSize, VkDeviceSize,
133 VkSharedBaseObj<VulkanBitstreamBuffer>&)
134 {
135 TCU_THROW(InternalError, "Presentation only interface from the samples app should not be needed in CTS");
136 }
137
138
CheckAccess(VkDeviceSize offset, VkDeviceSize size) const139 deUint8* BitstreamBufferImpl::CheckAccess(VkDeviceSize offset, VkDeviceSize size) const
140 {
141 DE_ASSERT(size > 0 && offset + size < m_bufferSize);
142 DE_UNREF(size);
143 auto* bitstreamBasePtr = static_cast<deUint8*>(m_bitstreamBuffer->getAllocation().getHostPtr());
144 return static_cast<deUint8*>(bitstreamBasePtr + offset);
145 }
146
MemsetData(deUint32 value, VkDeviceSize offset, VkDeviceSize size)147 int64_t BitstreamBufferImpl::MemsetData(deUint32 value, VkDeviceSize offset, VkDeviceSize size)
148 {
149 if (size == 0)
150 {
151 return 0;
152 }
153 auto* bitstreamBasePtr = static_cast<deUint8*>(m_bitstreamBuffer->getAllocation().getHostPtr());
154 deMemset(bitstreamBasePtr + offset, value, size);
155 vk::flushAlloc(m_devctx->getDeviceDriver(), m_devctx->device, m_bitstreamBuffer->getAllocation());
156 return size;
157 }
158
CopyDataToBuffer(deUint8* dstBuffer, VkDeviceSize dstOffset, VkDeviceSize srcOffset, VkDeviceSize size) const159 int64_t BitstreamBufferImpl::CopyDataToBuffer(deUint8* dstBuffer, VkDeviceSize dstOffset, VkDeviceSize srcOffset, VkDeviceSize size) const
160 {
161 if (size == 0)
162 {
163 return 0;
164 }
165 auto* bitstreamBasePtr = static_cast<deUint8*>(m_bitstreamBuffer->getAllocation().getHostPtr());
166 deMemcpy(dstBuffer + dstOffset, bitstreamBasePtr + srcOffset, size);
167 return size;
168 }
169
CopyDataToBuffer(VkSharedBaseObj<VulkanBitstreamBuffer>& dstBuffer, VkDeviceSize dstOffset, VkDeviceSize srcOffset, VkDeviceSize size) const170 int64_t BitstreamBufferImpl::CopyDataToBuffer(VkSharedBaseObj<VulkanBitstreamBuffer>& dstBuffer, VkDeviceSize dstOffset, VkDeviceSize srcOffset, VkDeviceSize size) const
171 {
172 if (size == 0)
173 {
174 return 0;
175 }
176 const deUint8* readData = CheckAccess(srcOffset, size);
177 DE_ASSERT(readData);
178 return dstBuffer->CopyDataFromBuffer(readData, 0, dstOffset, size);
179 }
180
CopyDataFromBuffer(const deUint8* sourceBuffer, VkDeviceSize srcOffset, VkDeviceSize dstOffset, VkDeviceSize size)181 int64_t BitstreamBufferImpl::CopyDataFromBuffer(const deUint8* sourceBuffer, VkDeviceSize srcOffset, VkDeviceSize dstOffset, VkDeviceSize size)
182 {
183 if (size == 0)
184 {
185 return 0;
186 }
187 auto* bitstreamBasePtr = static_cast<deUint8*>(m_bitstreamBuffer->getAllocation().getHostPtr());
188 deMemcpy(bitstreamBasePtr + dstOffset, sourceBuffer + srcOffset, size);
189 return size;
190 }
191
CopyDataFromBuffer(const VkSharedBaseObj<VulkanBitstreamBuffer>& sourceBuffer, VkDeviceSize srcOffset, VkDeviceSize dstOffset, VkDeviceSize size)192 int64_t BitstreamBufferImpl::CopyDataFromBuffer(const VkSharedBaseObj<VulkanBitstreamBuffer>& sourceBuffer,
193 VkDeviceSize srcOffset,
194 VkDeviceSize dstOffset,
195 VkDeviceSize size)
196 {
197 if (size == 0)
198 {
199 return 0;
200 }
201
202 const deUint8* readData = sourceBuffer->GetReadOnlyDataPtr(srcOffset, size);
203 DE_ASSERT(readData);
204
205 auto* bitstreamBasePtr = static_cast<deUint8*>(m_bitstreamBuffer->getAllocation().getHostPtr());
206 deMemcpy(bitstreamBasePtr + dstOffset, readData + srcOffset, size);
207 return size;
208 }
209
GetDataPtr(VkDeviceSize offset, VkDeviceSize& maxSize)210 deUint8* BitstreamBufferImpl::GetDataPtr(VkDeviceSize offset, VkDeviceSize& maxSize)
211 {
212 deUint8* readData = CheckAccess(offset, 1);
213 DE_ASSERT(readData);
214 maxSize = m_bufferSize - offset;
215 return readData;
216 }
217
GetReadOnlyDataPtr(VkDeviceSize offset, VkDeviceSize& maxSize) const218 const deUint8* BitstreamBufferImpl::GetReadOnlyDataPtr(VkDeviceSize offset, VkDeviceSize& maxSize) const
219 {
220 deUint8* readData = CheckAccess(offset, 1);
221 DE_ASSERT(readData);
222 maxSize = m_bufferSize - offset;
223 return readData;
224 }
225
FlushRange(VkDeviceSize , VkDeviceSize size) const226 void BitstreamBufferImpl::FlushRange(VkDeviceSize /*offset*/, VkDeviceSize size) const
227 {
228 if (size == 0)
229 {
230 return;
231 }
232
233 // TOOD: Plumb the size and offset alignment caps into this class to invalidate just the range asked for in the API, rather than the whole range.
234 vk::flushAlloc(m_devctx->getDeviceDriver(), m_devctx->device, m_bitstreamBuffer->getAllocation());
235 }
236
InvalidateRange(VkDeviceSize , VkDeviceSize size) const237 void BitstreamBufferImpl::InvalidateRange(VkDeviceSize /*offset*/, VkDeviceSize size) const
238 {
239 if (size == 0)
240 {
241 return;
242 }
243 // TOOD: Plumb the size and offset alignment caps into this class to invalidate just the range asked for in the API, rather than the whole range.
244 vk::flushAlloc(m_devctx->getDeviceDriver(), m_devctx->device, m_bitstreamBuffer->getAllocation());
245 }
246
AddStreamMarker(deUint32 streamOffset)247 deUint32 BitstreamBufferImpl::AddStreamMarker(deUint32 streamOffset)
248 {
249 m_streamMarkers.push_back(streamOffset);
250 return (deUint32)(m_streamMarkers.size() - 1);
251 }
252
SetStreamMarker(deUint32 streamOffset, deUint32 index)253 deUint32 BitstreamBufferImpl::SetStreamMarker(deUint32 streamOffset, deUint32 index)
254 {
255 DE_ASSERT(index < (deUint32)m_streamMarkers.size());
256 if (!(index < (deUint32)m_streamMarkers.size()))
257 {
258 return deUint32(-1);
259 }
260 m_streamMarkers[index] = streamOffset;
261 return index;
262 }
263
264 deUint32 BitstreamBufferImpl::GetStreamMarker(deUint32 index) const
265 {
266 DE_ASSERT(index < (deUint32)m_streamMarkers.size());
267 return m_streamMarkers[index];
268 }
269
270 deUint32 BitstreamBufferImpl::GetStreamMarkersCount() const
271 {
272 return (deUint32)m_streamMarkers.size();
273 }
274
275 const deUint32* BitstreamBufferImpl::GetStreamMarkersPtr(deUint32 startIndex, deUint32& maxCount) const
276 {
277 maxCount = (deUint32)m_streamMarkers.size() - startIndex;
278 return m_streamMarkers.data() + startIndex;
279 }
280
281 deUint32 BitstreamBufferImpl::ResetStreamMarkers()
282 {
283 deUint32 oldSize = (deUint32)m_streamMarkers.size();
284 m_streamMarkers.clear();
285 return oldSize;
286 }
287
288 } // namespace video
289 } // namespace vkt
290