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
Create(DeviceContext * devctx,uint32_t queueFamilyIndex,VkDeviceSize bufferSize,VkDeviceSize bufferOffsetAlignment,VkDeviceSize bufferSizeAlignment,VkSharedBaseObj<BitstreamBufferImpl> & vulkanBitstreamBuffer,const VkVideoProfileListInfoKHR * profileList,bool resourcesWithoutProfiles)48 VkResult BitstreamBufferImpl::Create(DeviceContext *devctx, uint32_t queueFamilyIndex, VkDeviceSize bufferSize,
49 VkDeviceSize bufferOffsetAlignment, VkDeviceSize bufferSizeAlignment,
50 VkSharedBaseObj<BitstreamBufferImpl> &vulkanBitstreamBuffer,
51 const VkVideoProfileListInfoKHR *profileList, bool resourcesWithoutProfiles)
52 {
53 VkSharedBaseObj<BitstreamBufferImpl> vkBitstreamBuffer(new BitstreamBufferImpl(
54 devctx, queueFamilyIndex, bufferOffsetAlignment, bufferSizeAlignment, profileList, resourcesWithoutProfiles));
55 DE_ASSERT(vkBitstreamBuffer);
56
57 VK_CHECK(vkBitstreamBuffer->Initialize(bufferSize));
58
59 vulkanBitstreamBuffer = vkBitstreamBuffer;
60
61 return VK_SUCCESS;
62 }
63
Initialize(VkDeviceSize bufferSize)64 VkResult BitstreamBufferImpl::Initialize(VkDeviceSize bufferSize)
65 {
66 auto &vk = m_devctx->getDeviceDriver();
67 auto device = m_devctx->device;
68
69 if (m_bufferSize >= bufferSize)
70 {
71 VkDeviceSize size = MemsetData(0x00, 0, m_bufferSize);
72 DE_ASSERT(size == m_bufferSize);
73 DE_UNREF(size);
74 return VK_SUCCESS;
75 }
76
77 VkBufferCreateInfo createBufferInfo = {};
78 createBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
79 createBufferInfo.pNext = m_resourcesWithoutProfiles ? nullptr : m_profileList;
80 createBufferInfo.size = deAlignSize(bufferSize, m_bufferSizeAlignment);
81 createBufferInfo.usage = VK_BUFFER_USAGE_VIDEO_DECODE_SRC_BIT_KHR;
82 createBufferInfo.flags = m_resourcesWithoutProfiles ? VK_BUFFER_CREATE_VIDEO_PROFILE_INDEPENDENT_BIT_KHR : 0;
83 createBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
84 createBufferInfo.queueFamilyIndexCount = 1;
85 createBufferInfo.pQueueFamilyIndices = &m_queueFamilyIndex;
86 m_bitstreamBuffer = BufferPtr(
87 new BufferWithMemory(vk, device, m_devctx->allocator(), createBufferInfo,
88 MemoryRequirement::HostVisible | MemoryRequirement::Coherent | MemoryRequirement::Cached));
89
90 m_bufferSize = bufferSize;
91
92 return VK_SUCCESS;
93 }
94
CopyDataToBuffer(const uint8_t * pData,VkDeviceSize size,VkDeviceSize & dstBufferOffset) const95 VkResult BitstreamBufferImpl::CopyDataToBuffer(const uint8_t *pData, VkDeviceSize size,
96 VkDeviceSize &dstBufferOffset) const
97 {
98 DE_ASSERT((pData != nullptr) && (size > 0) &&
99 (size < 10 * 1024 * 1024)); // 10 MiB should be big enough for any CTS test.
100
101 dstBufferOffset = deAlignSize(dstBufferOffset, m_bufferOffsetAlignment);
102 DE_ASSERT((dstBufferOffset + size) <= m_bufferSize);
103
104 auto *bitstreamBasePtr = static_cast<uint8_t *>(m_bitstreamBuffer->getAllocation().getHostPtr());
105 deMemcpy(bitstreamBasePtr + dstBufferOffset, pData, size);
106 vk::flushAlloc(m_devctx->getDeviceDriver(), m_devctx->device, m_bitstreamBuffer->getAllocation());
107
108 return VK_SUCCESS;
109 }
110
GetMaxSize() const111 VkDeviceSize BitstreamBufferImpl::GetMaxSize() const
112 {
113 return m_bufferSize;
114 }
115
GetOffsetAlignment() const116 VkDeviceSize BitstreamBufferImpl::GetOffsetAlignment() const
117 {
118 return m_bufferOffsetAlignment;
119 }
120
GetSizeAlignment() const121 VkDeviceSize BitstreamBufferImpl::GetSizeAlignment() const
122 {
123 // REVIEW: Cache this?
124 auto reqs = getBufferMemoryRequirements(m_devctx->getDeviceDriver(), m_devctx->device, m_bitstreamBuffer->get());
125 return reqs.alignment;
126 }
127
Resize(VkDeviceSize,VkDeviceSize,VkDeviceSize)128 VkDeviceSize BitstreamBufferImpl::Resize(VkDeviceSize, VkDeviceSize, VkDeviceSize)
129 {
130 TCU_THROW(InternalError, "Bitstream buffers should never need to be resized in the CTS");
131 }
132
Clone(VkDeviceSize,VkDeviceSize,VkDeviceSize,VkSharedBaseObj<VulkanBitstreamBuffer> &)133 VkDeviceSize BitstreamBufferImpl::Clone(VkDeviceSize, VkDeviceSize, VkDeviceSize,
134 VkSharedBaseObj<VulkanBitstreamBuffer> &)
135 {
136 TCU_THROW(InternalError, "Presentation only interface from the samples app should not be needed in CTS");
137 }
138
CheckAccess(VkDeviceSize offset,VkDeviceSize size) const139 uint8_t *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<uint8_t *>(m_bitstreamBuffer->getAllocation().getHostPtr());
144 return static_cast<uint8_t *>(bitstreamBasePtr + offset);
145 }
146
MemsetData(uint32_t value,VkDeviceSize offset,VkDeviceSize size)147 int64_t BitstreamBufferImpl::MemsetData(uint32_t value, VkDeviceSize offset, VkDeviceSize size)
148 {
149 if (size == 0)
150 {
151 return 0;
152 }
153 auto *bitstreamBasePtr = static_cast<uint8_t *>(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(uint8_t * dstBuffer,VkDeviceSize dstOffset,VkDeviceSize srcOffset,VkDeviceSize size) const159 int64_t BitstreamBufferImpl::CopyDataToBuffer(uint8_t *dstBuffer, VkDeviceSize dstOffset, VkDeviceSize srcOffset,
160 VkDeviceSize size) const
161 {
162 if (size == 0)
163 {
164 return 0;
165 }
166 auto *bitstreamBasePtr = static_cast<uint8_t *>(m_bitstreamBuffer->getAllocation().getHostPtr());
167 deMemcpy(dstBuffer + dstOffset, bitstreamBasePtr + srcOffset, size);
168 return size;
169 }
170
CopyDataToBuffer(VkSharedBaseObj<VulkanBitstreamBuffer> & dstBuffer,VkDeviceSize dstOffset,VkDeviceSize srcOffset,VkDeviceSize size) const171 int64_t BitstreamBufferImpl::CopyDataToBuffer(VkSharedBaseObj<VulkanBitstreamBuffer> &dstBuffer, VkDeviceSize dstOffset,
172 VkDeviceSize srcOffset, VkDeviceSize size) const
173 {
174 if (size == 0)
175 {
176 return 0;
177 }
178 const uint8_t *readData = CheckAccess(srcOffset, size);
179 DE_ASSERT(readData);
180 return dstBuffer->CopyDataFromBuffer(readData, 0, dstOffset, size);
181 }
182
CopyDataFromBuffer(const uint8_t * sourceBuffer,VkDeviceSize srcOffset,VkDeviceSize dstOffset,VkDeviceSize size)183 int64_t BitstreamBufferImpl::CopyDataFromBuffer(const uint8_t *sourceBuffer, VkDeviceSize srcOffset,
184 VkDeviceSize dstOffset, VkDeviceSize size)
185 {
186 if (size == 0)
187 {
188 return 0;
189 }
190 auto *bitstreamBasePtr = static_cast<uint8_t *>(m_bitstreamBuffer->getAllocation().getHostPtr());
191 deMemcpy(bitstreamBasePtr + dstOffset, sourceBuffer + srcOffset, size);
192 return size;
193 }
194
CopyDataFromBuffer(const VkSharedBaseObj<VulkanBitstreamBuffer> & sourceBuffer,VkDeviceSize srcOffset,VkDeviceSize dstOffset,VkDeviceSize size)195 int64_t BitstreamBufferImpl::CopyDataFromBuffer(const VkSharedBaseObj<VulkanBitstreamBuffer> &sourceBuffer,
196 VkDeviceSize srcOffset, VkDeviceSize dstOffset, VkDeviceSize size)
197 {
198 if (size == 0)
199 {
200 return 0;
201 }
202
203 VkDeviceSize maxSize;
204 const uint8_t *readData = sourceBuffer->GetReadOnlyDataPtr(srcOffset, maxSize);
205 DE_ASSERT(readData);
206 size = std::min(size, maxSize);
207 auto *bitstreamBasePtr = static_cast<uint8_t *>(m_bitstreamBuffer->getAllocation().getHostPtr());
208 deMemcpy(bitstreamBasePtr + dstOffset, readData + srcOffset, size);
209 return size;
210 }
211
GetDataPtr(VkDeviceSize offset,VkDeviceSize & maxSize)212 uint8_t *BitstreamBufferImpl::GetDataPtr(VkDeviceSize offset, VkDeviceSize &maxSize)
213 {
214 uint8_t *readData = CheckAccess(offset, 1);
215 DE_ASSERT(readData);
216 maxSize = m_bufferSize - offset;
217 return readData;
218 }
219
GetReadOnlyDataPtr(VkDeviceSize offset,VkDeviceSize & maxSize) const220 const uint8_t *BitstreamBufferImpl::GetReadOnlyDataPtr(VkDeviceSize offset, VkDeviceSize &maxSize) const
221 {
222 uint8_t *readData = CheckAccess(offset, 1);
223 DE_ASSERT(readData);
224 maxSize = m_bufferSize - offset;
225 return readData;
226 }
227
FlushRange(VkDeviceSize,VkDeviceSize size) const228 void BitstreamBufferImpl::FlushRange(VkDeviceSize /*offset*/, VkDeviceSize size) const
229 {
230 if (size == 0)
231 {
232 return;
233 }
234
235 // 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.
236 vk::flushAlloc(m_devctx->getDeviceDriver(), m_devctx->device, m_bitstreamBuffer->getAllocation());
237 }
238
InvalidateRange(VkDeviceSize,VkDeviceSize size) const239 void BitstreamBufferImpl::InvalidateRange(VkDeviceSize /*offset*/, VkDeviceSize size) const
240 {
241 if (size == 0)
242 {
243 return;
244 }
245 // 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.
246 vk::flushAlloc(m_devctx->getDeviceDriver(), m_devctx->device, m_bitstreamBuffer->getAllocation());
247 }
248
AddStreamMarker(uint32_t streamOffset)249 uint32_t BitstreamBufferImpl::AddStreamMarker(uint32_t streamOffset)
250 {
251 m_streamMarkers.push_back(streamOffset);
252 return (uint32_t)(m_streamMarkers.size() - 1);
253 }
254
SetStreamMarker(uint32_t streamOffset,uint32_t index)255 uint32_t BitstreamBufferImpl::SetStreamMarker(uint32_t streamOffset, uint32_t index)
256 {
257 DE_ASSERT(index < (uint32_t)m_streamMarkers.size());
258 if (!(index < (uint32_t)m_streamMarkers.size()))
259 {
260 return uint32_t(-1);
261 }
262 m_streamMarkers[index] = streamOffset;
263 return index;
264 }
265
GetStreamMarker(uint32_t index) const266 uint32_t BitstreamBufferImpl::GetStreamMarker(uint32_t index) const
267 {
268 DE_ASSERT(index < (uint32_t)m_streamMarkers.size());
269 return m_streamMarkers[index];
270 }
271
GetStreamMarkersCount() const272 uint32_t BitstreamBufferImpl::GetStreamMarkersCount() const
273 {
274 return (uint32_t)m_streamMarkers.size();
275 }
276
GetStreamMarkersPtr(uint32_t startIndex,uint32_t & maxCount) const277 const uint32_t *BitstreamBufferImpl::GetStreamMarkersPtr(uint32_t startIndex, uint32_t &maxCount) const
278 {
279 maxCount = (uint32_t)m_streamMarkers.size() - startIndex;
280 return m_streamMarkers.data() + startIndex;
281 }
282
ResetStreamMarkers()283 uint32_t BitstreamBufferImpl::ResetStreamMarkers()
284 {
285 uint32_t oldSize = (uint32_t)m_streamMarkers.size();
286 m_streamMarkers.clear();
287 return oldSize;
288 }
289
290 } // namespace video
291 } // namespace vkt
292