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