blob: c4d569c85e998ee2a812c8203732f6126c9d6935 [file] [log] [blame]
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -06001#include <vulkan.h>
2#include <vkDbg.h>
Tony Barbour30486ea2015-04-07 13:44:53 -06003#include "gtest-1.7.0/include/gtest/gtest.h"
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -06004#include "vkrenderframework.h"
Tony Barbour30486ea2015-04-07 13:44:53 -06005
Mark Lobodzinski5f25be42015-05-14 15:08:13 -05006#define GLM_FORCE_RADIANS
7#include "glm/glm.hpp"
8#include <glm/gtc/matrix_transform.hpp>
9
10//--------------------------------------------------------------------------------------
11// Mesh and VertexFormat Data
12//--------------------------------------------------------------------------------------
13struct Vertex
14{
15 float posX, posY, posZ, posW; // Position data
16 float r, g, b, a; // Color
17};
18
19#define XYZ1(_x_, _y_, _z_) (_x_), (_y_), (_z_), 1.f
20
21typedef enum _BsoFailSelect {
22 BsoFailNone = 0x00000000,
23 BsoFailRaster = 0x00000001,
24 BsoFailViewport = 0x00000002,
25 BsoFailColorBlend = 0x00000004,
26 BsoFailDepthStencil = 0x00000008,
27} BsoFailSelect;
28
29struct vktriangle_vs_uniform {
30 // Must start with MVP
31 float mvp[4][4];
32 float position[3][4];
33 float color[3][4];
34};
35
36static const char *bindStateVertShaderText =
37 "#version 130\n"
38 "vec2 vertices[3];\n"
39 "void main() {\n"
40 " vertices[0] = vec2(-1.0, -1.0);\n"
41 " vertices[1] = vec2( 1.0, -1.0);\n"
42 " vertices[2] = vec2( 0.0, 1.0);\n"
43 " gl_Position = vec4(vertices[gl_VertexID % 3], 0.0, 1.0);\n"
44 "}\n";
45
46static const char *bindStateFragShaderText =
47 "#version 130\n"
48 "void main() {\n"
49 " gl_FragColor = vec4(0,1,0,1);\n"
50 "}\n";
51
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -060052void VKAPI myDbgFunc(
53 VK_DBG_MSG_TYPE msgType,
Courtney Goeltzenleuchter382489d2015-04-10 08:34:15 -060054 VkValidationLevel validationLevel,
Mike Stroyan230e6252015-04-17 12:36:38 -060055 VkObject srcObject,
Tony Barbour30486ea2015-04-07 13:44:53 -060056 size_t location,
57 int32_t msgCode,
58 const char* pMsg,
59 void* pUserData);
60
61class ErrorMonitor {
62public:
Tony Barbour0c1bdc62015-04-29 17:34:29 -060063 ErrorMonitor()
Tony Barbour30486ea2015-04-07 13:44:53 -060064 {
Mike Stroyan09aae812015-05-12 16:00:45 -060065 pthread_mutexattr_t attr;
66 pthread_mutexattr_init(&attr);
67 pthread_mutex_init(&m_mutex, &attr);
68 pthread_mutex_lock(&m_mutex);
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -060069 m_msgType = VK_DBG_MSG_UNKNOWN;
Mike Stroyan09aae812015-05-12 16:00:45 -060070 m_bailout = NULL;
71 pthread_mutex_unlock(&m_mutex);
Tony Barbour30486ea2015-04-07 13:44:53 -060072 }
73 void ClearState()
74 {
Mike Stroyan09aae812015-05-12 16:00:45 -060075 pthread_mutex_lock(&m_mutex);
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -060076 m_msgType = VK_DBG_MSG_UNKNOWN;
Tony Barbour30486ea2015-04-07 13:44:53 -060077 m_msgString.clear();
Mike Stroyan09aae812015-05-12 16:00:45 -060078 pthread_mutex_unlock(&m_mutex);
Tony Barbour30486ea2015-04-07 13:44:53 -060079 }
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -060080 VK_DBG_MSG_TYPE GetState(std::string *msgString)
Tony Barbour30486ea2015-04-07 13:44:53 -060081 {
Mike Stroyan09aae812015-05-12 16:00:45 -060082 pthread_mutex_lock(&m_mutex);
Tony Barbour30486ea2015-04-07 13:44:53 -060083 *msgString = m_msgString;
Mike Stroyan09aae812015-05-12 16:00:45 -060084 pthread_mutex_unlock(&m_mutex);
Tony Barbour30486ea2015-04-07 13:44:53 -060085 return m_msgType;
86 }
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -060087 void SetState(VK_DBG_MSG_TYPE msgType, const char *msgString)
Tony Barbour30486ea2015-04-07 13:44:53 -060088 {
Mike Stroyan09aae812015-05-12 16:00:45 -060089 pthread_mutex_lock(&m_mutex);
90 if (m_bailout != NULL) {
91 *m_bailout = true;
92 }
Tony Barbour30486ea2015-04-07 13:44:53 -060093 m_msgType = msgType;
Tony Barbour8508b8e2015-04-09 10:48:04 -060094 m_msgString.reserve(strlen(msgString));
95 m_msgString = msgString;
Mike Stroyan09aae812015-05-12 16:00:45 -060096 pthread_mutex_unlock(&m_mutex);
97 }
98 void SetBailout(bool *bailout)
99 {
100 m_bailout = bailout;
Tony Barbour30486ea2015-04-07 13:44:53 -0600101 }
102
103private:
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -0600104 VK_DBG_MSG_TYPE m_msgType;
Mike Stroyan09aae812015-05-12 16:00:45 -0600105 std::string m_msgString;
106 pthread_mutex_t m_mutex;
107 bool* m_bailout;
Tony Barbour30486ea2015-04-07 13:44:53 -0600108};
Mark Lobodzinski5f25be42015-05-14 15:08:13 -0500109
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -0600110void VKAPI myDbgFunc(
Mike Stroyan230e6252015-04-17 12:36:38 -0600111 VK_DBG_MSG_TYPE msgType,
112 VkValidationLevel validationLevel,
113 VkObject srcObject,
Tony Barbour30486ea2015-04-07 13:44:53 -0600114 size_t location,
115 int32_t msgCode,
116 const char* pMsg,
117 void* pUserData)
118{
Tony Barbour8508b8e2015-04-09 10:48:04 -0600119 if (msgType == VK_DBG_MSG_WARNING || msgType == VK_DBG_MSG_ERROR) {
120 ErrorMonitor *errMonitor = (ErrorMonitor *)pUserData;
121 errMonitor->SetState(msgType, pMsg);
122 }
Tony Barbour30486ea2015-04-07 13:44:53 -0600123}
Mark Lobodzinski5f25be42015-05-14 15:08:13 -0500124
Tony Barbour01999182015-04-09 12:58:51 -0600125class VkLayerTest : public VkRenderFramework
Tony Barbour30486ea2015-04-07 13:44:53 -0600126{
127public:
Courtney Goeltzenleuchter382489d2015-04-10 08:34:15 -0600128 VkResult BeginCommandBuffer(VkCommandBufferObj &cmdBuffer);
129 VkResult EndCommandBuffer(VkCommandBufferObj &cmdBuffer);
Mark Lobodzinski5f25be42015-05-14 15:08:13 -0500130 void VKTriangleTest(const char *vertShaderText, const char *fragShaderText, BsoFailSelect failMask);
131 void GenericDrawPreparation(VkCommandBufferObj *cmdBuffer, VkPipelineObj &pipelineobj, VkDescriptorSetObj &descriptorSet, BsoFailSelect failMask);
Tony Barbour30486ea2015-04-07 13:44:53 -0600132
133protected:
Tony Barbour01999182015-04-09 12:58:51 -0600134 VkMemoryRefManager m_memoryRefManager;
135 ErrorMonitor *m_errorMonitor;
Tony Barbour30486ea2015-04-07 13:44:53 -0600136
137 virtual void SetUp() {
Mike Stroyan09aae812015-05-12 16:00:45 -0600138 const char *extension_names[] = {"MemTracker", "ObjectTracker", "Threading"};
139 const std::vector<const char *> extensions(extension_names,
140 extension_names + sizeof(extension_names)/sizeof(extension_names[0]));
Tony Barbour950ebc02015-04-23 12:55:36 -0600141
142 size_t extSize = sizeof(uint32_t);
143 uint32_t extCount = 0;
Tony Barbour04ada4a2015-04-23 15:28:27 -0600144 VkResult U_ASSERT_ONLY err;
Tony Barbour950ebc02015-04-23 12:55:36 -0600145 err = vkGetGlobalExtensionInfo(VK_EXTENSION_INFO_TYPE_COUNT, 0, &extSize, &extCount);
146 assert(!err);
147
148 VkExtensionProperties extProp;
149 extSize = sizeof(VkExtensionProperties);
150 bool32_t extFound;
151
Tony Barbour04ada4a2015-04-23 15:28:27 -0600152 for (uint32_t i = 0; i < extensions.size(); i++) {
Tony Barbour950ebc02015-04-23 12:55:36 -0600153 extFound = 0;
154 for (uint32_t j = 0; j < extCount; j++) {
155 err = vkGetGlobalExtensionInfo(VK_EXTENSION_INFO_TYPE_PROPERTIES, j, &extSize, &extProp);
Tony Barbour04ada4a2015-04-23 15:28:27 -0600156 assert(!err);
157 if (!strcmp(extensions[i], extProp.extName)) {
Tony Barbour950ebc02015-04-23 12:55:36 -0600158 extFound = 1;
159 break;
160 }
161 }
Tony Barbour04ada4a2015-04-23 15:28:27 -0600162 ASSERT_EQ(extFound, 1) << "ERROR: Cannot find extension named " << extensions[i] << " which is necessary to pass this test";
Tony Barbour950ebc02015-04-23 12:55:36 -0600163 }
Tony Barbour30486ea2015-04-07 13:44:53 -0600164
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -0600165 this->app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
Tony Barbour30486ea2015-04-07 13:44:53 -0600166 this->app_info.pNext = NULL;
167 this->app_info.pAppName = "layer_tests";
168 this->app_info.appVersion = 1;
169 this->app_info.pEngineName = "unittest";
170 this->app_info.engineVersion = 1;
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -0600171 this->app_info.apiVersion = VK_API_VERSION;
Tony Barbour30486ea2015-04-07 13:44:53 -0600172
Tony Barbour0c1bdc62015-04-29 17:34:29 -0600173 m_errorMonitor = new ErrorMonitor;
174 InitFramework(extensions, myDbgFunc, m_errorMonitor);
175
Tony Barbour30486ea2015-04-07 13:44:53 -0600176 }
177
178 virtual void TearDown() {
179 // Clean up resources before we reset
Tony Barbour30486ea2015-04-07 13:44:53 -0600180 ShutdownFramework();
Tony Barbour8508b8e2015-04-09 10:48:04 -0600181 delete m_errorMonitor;
Tony Barbour30486ea2015-04-07 13:44:53 -0600182 }
183};
Mark Lobodzinski5f25be42015-05-14 15:08:13 -0500184
Courtney Goeltzenleuchter382489d2015-04-10 08:34:15 -0600185VkResult VkLayerTest::BeginCommandBuffer(VkCommandBufferObj &cmdBuffer)
Tony Barbour30486ea2015-04-07 13:44:53 -0600186{
Courtney Goeltzenleuchter382489d2015-04-10 08:34:15 -0600187 VkResult result;
Tony Barbour30486ea2015-04-07 13:44:53 -0600188
189 result = cmdBuffer.BeginCommandBuffer();
190
191 /*
192 * For render test all drawing happens in a single render pass
193 * on a single command buffer.
194 */
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -0600195 if (VK_SUCCESS == result) {
Tony Barbour30486ea2015-04-07 13:44:53 -0600196 cmdBuffer.BeginRenderPass(renderPass(), framebuffer());
197 }
198
199 return result;
200}
201
Courtney Goeltzenleuchter382489d2015-04-10 08:34:15 -0600202VkResult VkLayerTest::EndCommandBuffer(VkCommandBufferObj &cmdBuffer)
Tony Barbour30486ea2015-04-07 13:44:53 -0600203{
Courtney Goeltzenleuchter382489d2015-04-10 08:34:15 -0600204 VkResult result;
Tony Barbour30486ea2015-04-07 13:44:53 -0600205
206 cmdBuffer.EndRenderPass(renderPass());
207
208 result = cmdBuffer.EndCommandBuffer();
209
210 return result;
211}
212
Mark Lobodzinski5f25be42015-05-14 15:08:13 -0500213void VkLayerTest::VKTriangleTest(const char *vertShaderText, const char *fragShaderText, BsoFailSelect failMask)
214{
215 // Create identity matrix
216 int i;
217 struct vktriangle_vs_uniform data;
218
219 glm::mat4 Projection = glm::mat4(1.0f);
220 glm::mat4 View = glm::mat4(1.0f);
221 glm::mat4 Model = glm::mat4(1.0f);
222 glm::mat4 MVP = Projection * View * Model;
223 const int matrixSize = sizeof(MVP);
224 const int bufSize = sizeof(vktriangle_vs_uniform) / sizeof(float);
225
226 memcpy(&data.mvp, &MVP[0][0], matrixSize);
227
228 static const Vertex tri_data[] =
229 {
230 { XYZ1( -1, -1, 0 ), XYZ1( 1.f, 0.f, 0.f ) },
231 { XYZ1( 1, -1, 0 ), XYZ1( 0.f, 1.f, 0.f ) },
232 { XYZ1( 0, 1, 0 ), XYZ1( 0.f, 0.f, 1.f ) },
233 };
234
235 for (i=0; i<3; i++) {
236 data.position[i][0] = tri_data[i].posX;
237 data.position[i][1] = tri_data[i].posY;
238 data.position[i][2] = tri_data[i].posZ;
239 data.position[i][3] = tri_data[i].posW;
240 data.color[i][0] = tri_data[i].r;
241 data.color[i][1] = tri_data[i].g;
242 data.color[i][2] = tri_data[i].b;
243 data.color[i][3] = tri_data[i].a;
244 }
245
246 ASSERT_NO_FATAL_FAILURE(InitState());
247 ASSERT_NO_FATAL_FAILURE(InitViewport());
248
249 VkConstantBufferObj constantBuffer(m_device, bufSize*2, sizeof(float), (const void*) &data);
250
251 VkShaderObj vs(m_device,vertShaderText,VK_SHADER_STAGE_VERTEX, this);
252 VkShaderObj ps(m_device,fragShaderText, VK_SHADER_STAGE_FRAGMENT, this);
253
254 VkPipelineObj pipelineobj(m_device);
255 pipelineobj.AddShader(&vs);
256 pipelineobj.AddShader(&ps);
257
258 VkDescriptorSetObj descriptorSet(m_device);
259 descriptorSet.AppendBuffer(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, constantBuffer);
260
261 ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
262 VkCommandBufferObj cmdBuffer(m_device);
263 cmdBuffer.AddRenderTarget(m_renderTargets[0]);
264
265 ASSERT_VK_SUCCESS(BeginCommandBuffer(cmdBuffer));
266
267 GenericDrawPreparation(&cmdBuffer, pipelineobj, descriptorSet, failMask);
268
269 // render triangle
270 cmdBuffer.Draw(0, 3, 0, 1);
271
272 // finalize recording of the command buffer
273 EndCommandBuffer(cmdBuffer);
274
275 cmdBuffer.QueueCommandBuffer();
276}
277
278void VkLayerTest::GenericDrawPreparation(VkCommandBufferObj *cmdBuffer, VkPipelineObj &pipelineobj, VkDescriptorSetObj &descriptorSet, BsoFailSelect failMask)
279{
280 if (m_depthStencil->Initialized()) {
281 cmdBuffer->ClearAllBuffers(m_clear_color, m_depth_clear_color, m_stencil_clear_color, m_depthStencil);
282 } else {
283 cmdBuffer->ClearAllBuffers(m_clear_color, m_depth_clear_color, m_stencil_clear_color, NULL);
284 }
285
286 cmdBuffer->PrepareAttachments();
287 if ((failMask & BsoFailRaster) != BsoFailRaster) {
288 cmdBuffer->BindStateObject(VK_STATE_BIND_POINT_RASTER, m_stateRaster);
289 }
290 if ((failMask & BsoFailViewport) != BsoFailViewport) {
291 cmdBuffer->BindStateObject(VK_STATE_BIND_POINT_VIEWPORT, m_stateViewport);
292 }
293 if ((failMask & BsoFailColorBlend) != BsoFailColorBlend) {
294 cmdBuffer->BindStateObject(VK_STATE_BIND_POINT_COLOR_BLEND, m_colorBlend);
295 }
296 if ((failMask & BsoFailDepthStencil) != BsoFailDepthStencil) {
297 cmdBuffer->BindStateObject(VK_STATE_BIND_POINT_DEPTH_STENCIL, m_stateDepthStencil);
298 }
299 descriptorSet.CreateVKDescriptorSet(cmdBuffer);
300 pipelineobj.CreateVKPipeline(descriptorSet);
301 cmdBuffer->BindPipeline(pipelineobj);
302 cmdBuffer->BindDescriptorSet(descriptorSet);
303}
304
305// ********************************************************************************************************************
306// ********************************************************************************************************************
307// ********************************************************************************************************************
308// ********************************************************************************************************************
309
310TEST_F(VkLayerTest, MapMemWithoutHostVisibleBit)
311{
312 VK_DBG_MSG_TYPE msgType;
313 std::string msgString;
314 VkResult err;
315
316 ASSERT_NO_FATAL_FAILURE(InitState());
317 m_errorMonitor->ClearState();
318
319 // Create an image, allocate memory, free it, and then try to bind it
320 VkImage image;
321 VkDeviceMemory *mem;
322 VkMemoryRequirements *mem_reqs;
323
324 const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM;
325 const int32_t tex_width = 32;
326 const int32_t tex_height = 32;
327 size_t mem_reqs_size = sizeof(VkMemoryRequirements);
328 uint32_t num_allocations = 0;
329 size_t num_alloc_size = sizeof(num_allocations);
330
331 const VkImageCreateInfo image_create_info = {
332 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
333 .pNext = NULL,
334 .imageType = VK_IMAGE_TYPE_2D,
335 .format = tex_format,
336 .extent = { tex_width, tex_height, 1 },
337 .mipLevels = 1,
338 .arraySize = 1,
339 .samples = 1,
340 .tiling = VK_IMAGE_TILING_LINEAR,
341 .usage = VK_IMAGE_USAGE_SAMPLED_BIT,
342 .flags = 0,
343 };
344 VkMemoryAllocInfo mem_alloc = {
345 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
346 .pNext = NULL,
347 .allocationSize = 0,
348 // Introduce failure, do NOT set memProps to VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
349 .memProps = 0,
350 .memPriority = VK_MEMORY_PRIORITY_NORMAL,
351 };
352
353 err = vkCreateImage(m_device->device(), &image_create_info, &image);
354 ASSERT_VK_SUCCESS(err);
355
356 err = vkGetObjectInfo(m_device->device(),
357 VK_OBJECT_TYPE_IMAGE,
358 image,
359 VK_OBJECT_INFO_TYPE_MEMORY_ALLOCATION_COUNT,
360 &num_alloc_size,
361 &num_allocations);
362 ASSERT_VK_SUCCESS(err);
363
364 mem_reqs = new VkMemoryRequirements[num_allocations];
365 mem = new VkDeviceMemory[num_allocations];
366
367 err = vkGetObjectInfo(m_device->device(),
368 VK_OBJECT_TYPE_IMAGE,
369 image,
370 VK_OBJECT_INFO_TYPE_MEMORY_REQUIREMENTS,
371 &mem_reqs_size,
372 mem_reqs);
373 ASSERT_VK_SUCCESS(err);
374
375 mem_alloc.allocationSize = mem_reqs[0].size;
376
377 // allocate memory
378 err = vkAllocMemory(m_device->device(), &mem_alloc, &(mem[0]));
379 ASSERT_VK_SUCCESS(err);
380
381 // Try to bind free memory that has been freed
382 err = vkBindObjectMemory(m_device->device(), VK_OBJECT_TYPE_IMAGE, image, 0, mem[0], 0);
383 ASSERT_VK_SUCCESS(err);
384
385 // Map memory as if to initialize the image
386 void *mappedAddress = NULL;
387 err = vkMapMemory(m_device->device(), mem[0], 0, 0, 0, &mappedAddress);
388
389 msgType = m_errorMonitor->GetState(&msgString);
390 ASSERT_EQ(msgType, VK_DBG_MSG_ERROR) << "Did not receive an error while tring to map memory not visible to CPU";
391 if (!strstr(msgString.c_str(),"Mapping Memory without VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT")) {
392 FAIL() << "Error received did not match expected error message from vkMapMemory in MemTracker";
393 }
394}
395
396TEST_F(VkLayerTest, BindInvalidMemory)
397{
398 VK_DBG_MSG_TYPE msgType;
399 std::string msgString;
400 VkResult err;
401
402 ASSERT_NO_FATAL_FAILURE(InitState());
403 m_errorMonitor->ClearState();
404
405 // Create an image, allocate memory, free it, and then try to bind it
406 VkImage image;
407 VkDeviceMemory *mem;
408 VkMemoryRequirements *mem_reqs;
409
410 const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM;
411 const int32_t tex_width = 32;
412 const int32_t tex_height = 32;
413 size_t mem_reqs_size = sizeof(VkMemoryRequirements);
414 uint32_t num_allocations = 0;
415 size_t num_alloc_size = sizeof(num_allocations);
416
417 const VkImageCreateInfo image_create_info = {
418 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
419 .pNext = NULL,
420 .imageType = VK_IMAGE_TYPE_2D,
421 .format = tex_format,
422 .extent = { tex_width, tex_height, 1 },
423 .mipLevels = 1,
424 .arraySize = 1,
425 .samples = 1,
426 .tiling = VK_IMAGE_TILING_LINEAR,
427 .usage = VK_IMAGE_USAGE_SAMPLED_BIT,
428 .flags = 0,
429 };
430 VkMemoryAllocInfo mem_alloc = {
431 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
432 .pNext = NULL,
433 .allocationSize = 0,
434 .memProps = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
435 .memPriority = VK_MEMORY_PRIORITY_NORMAL,
436 };
437
438 err = vkCreateImage(m_device->device(), &image_create_info, &image);
439 ASSERT_VK_SUCCESS(err);
440
441 err = vkGetObjectInfo(m_device->device(),
442 VK_OBJECT_TYPE_IMAGE,
443 image,
444 VK_OBJECT_INFO_TYPE_MEMORY_ALLOCATION_COUNT,
445 &num_alloc_size,
446 &num_allocations);
447 ASSERT_VK_SUCCESS(err);
448
449 mem_reqs = new VkMemoryRequirements[num_allocations];
450 mem = new VkDeviceMemory[num_allocations];
451
452 err = vkGetObjectInfo(m_device->device(),
453 VK_OBJECT_TYPE_IMAGE,
454 image,
455 VK_OBJECT_INFO_TYPE_MEMORY_REQUIREMENTS,
456 &mem_reqs_size,
457 mem_reqs);
458 ASSERT_VK_SUCCESS(err);
459
460 mem_alloc.allocationSize = mem_reqs[0].size;
461
462 // allocate memory
463 err = vkAllocMemory(m_device->device(), &mem_alloc, &(mem[0]));
464 ASSERT_VK_SUCCESS(err);
465
466 // Introduce validation failure, free memory before binding
467 vkFreeMemory(m_device->device(), mem[0]);
468 ASSERT_VK_SUCCESS(err);
469
470 // Try to bind free memory that has been freed
471 err = vkBindObjectMemory(m_device->device(), VK_OBJECT_TYPE_IMAGE, image, 0, mem[0], 0);
472 ASSERT_VK_SUCCESS(err);
473
474 msgType = m_errorMonitor->GetState(&msgString);
475 ASSERT_EQ(msgType, VK_DBG_MSG_ERROR) << "Did not receive an error while tring to bind a freed memory object";
476 if (!strstr(msgString.c_str(),"Unable to set object")) {
477 FAIL() << "Error received did not match expected error message from BindObjectMemory in MemTracker";
478 }
479}
480
481TEST_F(VkLayerTest, FreeBoundMemory)
482{
483 VK_DBG_MSG_TYPE msgType;
484 std::string msgString;
485 VkResult err;
486
487 ASSERT_NO_FATAL_FAILURE(InitState());
488 m_errorMonitor->ClearState();
489
490 // Create an image, allocate memory, free it, and then try to bind it
491 VkImage image;
492 VkDeviceMemory *mem;
493 VkMemoryRequirements *mem_reqs;
494
495 const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM;
496 const int32_t tex_width = 32;
497 const int32_t tex_height = 32;
498 size_t mem_reqs_size = sizeof(VkMemoryRequirements);
499 uint32_t num_allocations = 0;
500 size_t num_alloc_size = sizeof(num_allocations);
501
502 const VkImageCreateInfo image_create_info = {
503 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
504 .pNext = NULL,
505 .imageType = VK_IMAGE_TYPE_2D,
506 .format = tex_format,
507 .extent = { tex_width, tex_height, 1 },
508 .mipLevels = 1,
509 .arraySize = 1,
510 .samples = 1,
511 .tiling = VK_IMAGE_TILING_LINEAR,
512 .usage = VK_IMAGE_USAGE_SAMPLED_BIT,
513 .flags = 0,
514 };
515 VkMemoryAllocInfo mem_alloc = {
516 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
517 .pNext = NULL,
518 .allocationSize = 0,
519 .memProps = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
520 .memPriority = VK_MEMORY_PRIORITY_NORMAL,
521 };
522
523 err = vkCreateImage(m_device->device(), &image_create_info, &image);
524 ASSERT_VK_SUCCESS(err);
525
526 err = vkGetObjectInfo(m_device->device(),
527 VK_OBJECT_TYPE_IMAGE,
528 image,
529 VK_OBJECT_INFO_TYPE_MEMORY_ALLOCATION_COUNT,
530 &num_alloc_size,
531 &num_allocations);
532 ASSERT_VK_SUCCESS(err);
533
534 mem_reqs = new VkMemoryRequirements[num_allocations];
535 mem = new VkDeviceMemory[num_allocations];
536
537 err = vkGetObjectInfo(m_device->device(),
538 VK_OBJECT_TYPE_IMAGE,
539 image,
540 VK_OBJECT_INFO_TYPE_MEMORY_REQUIREMENTS,
541 &mem_reqs_size,
542 mem_reqs);
543 ASSERT_VK_SUCCESS(err);
544
545 mem_alloc.allocationSize = mem_reqs[0].size;
546
547 // allocate memory
548 err = vkAllocMemory(m_device->device(), &mem_alloc, &(mem[0]));
549 ASSERT_VK_SUCCESS(err);
550
551 // Bind memory to Image object
552 err = vkBindObjectMemory(m_device->device(), VK_OBJECT_TYPE_IMAGE, image, 0, mem[0], 0);
553 ASSERT_VK_SUCCESS(err);
554
555 // Introduce validation failure, free memory while still bound to object
556 vkFreeMemory(m_device->device(), mem[0]);
557 ASSERT_VK_SUCCESS(err);
558
559 msgType = m_errorMonitor->GetState(&msgString);
560 ASSERT_EQ(msgType, VK_DBG_MSG_WARNING) << "Did not receive an warning while tring to free bound memory";
561 if (!strstr(msgString.c_str(),"Freeing memory object while it still has references")) {
562 FAIL() << "Warning received did not match expected message from freeMemObjInfo in MemTracker";
563 }
564}
565
566
567TEST_F(VkLayerTest, BindMemoryToDestroyedObject)
568{
569 VK_DBG_MSG_TYPE msgType;
570 std::string msgString;
571 VkResult err;
572
573 ASSERT_NO_FATAL_FAILURE(InitState());
574 m_errorMonitor->ClearState();
575
576 // Create an image object, allocate memory, destroy the object and then try to bind it
577 VkImage image;
578 VkDeviceMemory *mem;
579 VkMemoryRequirements *mem_reqs;
580
581 const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM;
582 const int32_t tex_width = 32;
583 const int32_t tex_height = 32;
584 size_t mem_reqs_size = sizeof(VkMemoryRequirements);
585 uint32_t num_allocations = 0;
586 size_t num_alloc_size = sizeof(num_allocations);
587
588 const VkImageCreateInfo image_create_info = {
589 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
590 .pNext = NULL,
591 .imageType = VK_IMAGE_TYPE_2D,
592 .format = tex_format,
593 .extent = { tex_width, tex_height, 1 },
594 .mipLevels = 1,
595 .arraySize = 1,
596 .samples = 1,
597 .tiling = VK_IMAGE_TILING_LINEAR,
598 .usage = VK_IMAGE_USAGE_SAMPLED_BIT,
599 .flags = 0,
600 };
601 VkMemoryAllocInfo mem_alloc = {
602 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
603 .pNext = NULL,
604 .allocationSize = 0,
605 .memProps = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
606 .memPriority = VK_MEMORY_PRIORITY_NORMAL,
607 };
608
609 err = vkCreateImage(m_device->device(), &image_create_info, &image);
610 ASSERT_VK_SUCCESS(err);
611
612 err = vkGetObjectInfo(m_device->device(),
613 VK_OBJECT_TYPE_IMAGE,
614 image,
615 VK_OBJECT_INFO_TYPE_MEMORY_ALLOCATION_COUNT,
616 &num_alloc_size,
617 &num_allocations);
618 ASSERT_VK_SUCCESS(err);
619
620 mem_reqs = new VkMemoryRequirements[num_allocations];
621 mem = new VkDeviceMemory[num_allocations];
622
623 err = vkGetObjectInfo(m_device->device(),
624 VK_OBJECT_TYPE_IMAGE,
625 image,
626 VK_OBJECT_INFO_TYPE_MEMORY_REQUIREMENTS,
627 &mem_reqs_size,
628 mem_reqs);
629 ASSERT_VK_SUCCESS(err);
630
631 mem_alloc.allocationSize = mem_reqs[0].size;
632
633 // Allocate memory
634 err = vkAllocMemory(m_device->device(), &mem_alloc, &(mem[0]));
635 ASSERT_VK_SUCCESS(err);
636
637 // Introduce validation failure, destroy Image object before binding
638 vkDestroyObject(m_device->device(), VK_OBJECT_TYPE_IMAGE, image);
639 ASSERT_VK_SUCCESS(err);
640
641 // Now Try to bind memory to this destroyted object
642 err = vkBindObjectMemory(m_device->device(), VK_OBJECT_TYPE_IMAGE, image, 0, mem[0], 0);
643 ASSERT_VK_SUCCESS(err);
644
645 msgType = m_errorMonitor->GetState(&msgString);
646 ASSERT_EQ(msgType, VK_DBG_MSG_ERROR) << "Did not receive an error while binding memory to a destroyed object";
647 if (!strstr(msgString.c_str(),"Unable to set object")) {
648 FAIL() << "Error received did not match expected error message from updateObjectBinding in MemTracker";
649 }
650}
651
Tony Barbour8508b8e2015-04-09 10:48:04 -0600652TEST_F(VkLayerTest, SubmitSignaledFence)
Tony Barbour30486ea2015-04-07 13:44:53 -0600653{
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -0600654 vk_testing::Fence testFence;
655 VK_DBG_MSG_TYPE msgType;
Tony Barbour30486ea2015-04-07 13:44:53 -0600656 std::string msgString;
Courtney Goeltzenleuchter382489d2015-04-10 08:34:15 -0600657
658 VkFenceCreateInfo fenceInfo = {};
Tony Barbour8508b8e2015-04-09 10:48:04 -0600659 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
660 fenceInfo.pNext = NULL;
661 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
Tony Barbour30486ea2015-04-07 13:44:53 -0600662
Tony Barbour30486ea2015-04-07 13:44:53 -0600663 ASSERT_NO_FATAL_FAILURE(InitState());
664 ASSERT_NO_FATAL_FAILURE(InitViewport());
665 ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
666
Tony Barbour01999182015-04-09 12:58:51 -0600667 VkCommandBufferObj cmdBuffer(m_device);
Tony Barbour30486ea2015-04-07 13:44:53 -0600668 cmdBuffer.AddRenderTarget(m_renderTargets[0]);
669
Tony Barbour8508b8e2015-04-09 10:48:04 -0600670 BeginCommandBuffer(cmdBuffer);
Tony Barbour30486ea2015-04-07 13:44:53 -0600671 cmdBuffer.ClearAllBuffers(m_clear_color, m_depth_clear_color, m_stencil_clear_color, NULL);
Tony Barbour8508b8e2015-04-09 10:48:04 -0600672 EndCommandBuffer(cmdBuffer);
Tony Barbour30486ea2015-04-07 13:44:53 -0600673
674 testFence.init(*m_device, fenceInfo);
675 m_errorMonitor->ClearState();
Tony Barbour8508b8e2015-04-09 10:48:04 -0600676 cmdBuffer.QueueCommandBuffer(testFence.obj());
Tony Barbour30486ea2015-04-07 13:44:53 -0600677 msgType = m_errorMonitor->GetState(&msgString);
Tony Barbour8508b8e2015-04-09 10:48:04 -0600678 ASSERT_EQ(msgType, VK_DBG_MSG_ERROR) << "Did not receive an err from using a fence in SIGNALED state in call to vkQueueSubmit";
679 if (!strstr(msgString.c_str(),"submitted in SIGNALED state. Fences must be reset before being submitted")) {
Mark Lobodzinski5f25be42015-05-14 15:08:13 -0500680 FAIL() << "Error received was not 'VkQueueSubmit with fence in SIGNALED_STATE'";
Tony Barbour8508b8e2015-04-09 10:48:04 -0600681 }
682
683}
684
685TEST_F(VkLayerTest, ResetUnsignaledFence)
686{
687 vk_testing::Fence testFence;
688 VK_DBG_MSG_TYPE msgType;
689 std::string msgString;
Courtney Goeltzenleuchter382489d2015-04-10 08:34:15 -0600690 VkFenceCreateInfo fenceInfo = {};
Tony Barbour8508b8e2015-04-09 10:48:04 -0600691 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
692 fenceInfo.pNext = NULL;
693
Tony Barbour8508b8e2015-04-09 10:48:04 -0600694 ASSERT_NO_FATAL_FAILURE(InitState());
695 testFence.init(*m_device, fenceInfo);
696 m_errorMonitor->ClearState();
Courtney Goeltzenleuchter382489d2015-04-10 08:34:15 -0600697 VkFence fences[1] = {testFence.obj()};
Tony Barbour8508b8e2015-04-09 10:48:04 -0600698 vkResetFences(m_device->device(), 1, fences);
699 msgType = m_errorMonitor->GetState(&msgString);
700 ASSERT_EQ(msgType, VK_DBG_MSG_ERROR) << "Did not receive an error from submitting fence with UNSIGNALED state to vkResetFences";
Tony Barbour01999182015-04-09 12:58:51 -0600701 if (!strstr(msgString.c_str(),"submitted to VkResetFences in UNSIGNALED STATE")) {
Mark Lobodzinski5f25be42015-05-14 15:08:13 -0500702 FAIL() << "Error received was not 'VkResetFences with fence in UNSIGNALED_STATE'";
Tony Barbour8508b8e2015-04-09 10:48:04 -0600703 }
Tony Barbour30486ea2015-04-07 13:44:53 -0600704
705}
706
Tony Barbour54cdd192015-04-22 15:12:07 -0600707TEST_F(VkLayerTest, WaitForUnsubmittedFence)
708{
709 vk_testing::Fence testFence;
710 VK_DBG_MSG_TYPE msgType;
711 std::string msgString;
712 VkFenceCreateInfo fenceInfo = {};
713 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
714 fenceInfo.pNext = NULL;
715
Tony Barbour54cdd192015-04-22 15:12:07 -0600716 ASSERT_NO_FATAL_FAILURE(InitState());
717 testFence.init(*m_device, fenceInfo);
718 m_errorMonitor->ClearState();
719 vkGetFenceStatus(m_device->device(),testFence.obj());
720 msgType = m_errorMonitor->GetState(&msgString);
721 ASSERT_EQ(msgType, VK_DBG_MSG_ERROR) << "Did not receive an error asking for status of unsubmitted fence";
722 if (!strstr(msgString.c_str(),"Status Requested for Unsubmitted Fence")) {
723 FAIL() << "Error received was not Status Requested for Unsubmitted Fence";
724 }
725
726 VkFence fences[1] = {testFence.obj()};
727 m_errorMonitor->ClearState();
728 vkWaitForFences(m_device->device(), 1, fences, VK_TRUE, 0);
729 msgType = m_errorMonitor->GetState(&msgString);
730 ASSERT_EQ(msgType, VK_DBG_MSG_ERROR) << "Did not receive an error for waiting for unsubmitted fence";
731 if (!strstr(msgString.c_str(),"Waiting for Unsubmitted Fence")) {
Mark Lobodzinski5f25be42015-05-14 15:08:13 -0500732 FAIL() << "Error received was not 'Waiting for Unsubmitted Fence'";
Tony Barbour54cdd192015-04-22 15:12:07 -0600733 }
734}
735
Tony Barbourdb686622015-05-06 09:35:56 -0600736TEST_F(VkLayerTest, GetObjectInfoMismatchedType)
737{
738 VkEventCreateInfo event_info;
739 VkEvent event;
740 VkMemoryRequirements mem_req;
741 size_t data_size = sizeof(mem_req);
742 VK_DBG_MSG_TYPE msgType;
743 std::string msgString;
744 VkResult err;
745
746 ASSERT_NO_FATAL_FAILURE(InitState());
747 memset(&event_info, 0, sizeof(event_info));
748 event_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO;
749
750 err = vkCreateEvent(device(), &event_info, &event);
751 ASSERT_VK_SUCCESS(err);
752 m_errorMonitor->ClearState();
753 err = vkGetObjectInfo(device(), VK_OBJECT_TYPE_IMAGE, event, VK_OBJECT_INFO_TYPE_MEMORY_REQUIREMENTS,
754 &data_size, &mem_req);
755 msgType = m_errorMonitor->GetState(&msgString);
756 ASSERT_EQ(msgType, VK_DBG_MSG_ERROR) << "Did not receive an error from mismatched types in vkGetObjectInfo";
757 if (!strstr(msgString.c_str(),"does not match designated type")) {
Mark Lobodzinski5f25be42015-05-14 15:08:13 -0500758 FAIL() << "Error received was not 'does not match designated type'";
Tony Barbourdb686622015-05-06 09:35:56 -0600759 }
Mark Lobodzinski5f25be42015-05-14 15:08:13 -0500760}
Tony Barbourdb686622015-05-06 09:35:56 -0600761
Mark Lobodzinski5f25be42015-05-14 15:08:13 -0500762TEST_F(VkLayerTest, RasterStateNotBound)
763{
764 VK_DBG_MSG_TYPE msgType;
765 std::string msgString;
766
767 TEST_DESCRIPTION("Simple Draw Call that validates failure when a raster state object is not bound beforehand");
768
769 VKTriangleTest(bindStateVertShaderText, bindStateFragShaderText, BsoFailRaster);
770
771 msgType = m_errorMonitor->GetState(&msgString);
772 ASSERT_EQ(msgType, VK_DBG_MSG_ERROR) << "Did not receive an error from Not Binding a Raster State Object";
773 if (!strstr(msgString.c_str(),"Raster object not bound to this command buffer")) {
774 FAIL() << "Error received was not 'Raster object not bound to this command buffer'";
775 }
776}
777
778TEST_F(VkLayerTest, ViewportStateNotBound)
779{
780 VK_DBG_MSG_TYPE msgType;
781 std::string msgString;
782 TEST_DESCRIPTION("Simple Draw Call that validates failure when a viewport state object is not bound beforehand");
783
784 VKTriangleTest(bindStateVertShaderText, bindStateFragShaderText, BsoFailViewport);
785
786 msgType = m_errorMonitor->GetState(&msgString);
787 ASSERT_EQ(msgType, VK_DBG_MSG_ERROR) << "Did not receive an error from Not Binding a Viewport State Object";
788 if (!strstr(msgString.c_str(),"Viewport object not bound to this command buffer")) {
789 FAIL() << "Error received was not 'Viewport object not bound to this command buffer'";
790 }
791}
792
793TEST_F(VkLayerTest, ColorBlendStateNotBound)
794{
795 VK_DBG_MSG_TYPE msgType;
796 std::string msgString;
797
798 TEST_DESCRIPTION("Simple Draw Call that validates failure when a color-blend state object is not bound beforehand");
799
800 VKTriangleTest(bindStateVertShaderText, bindStateFragShaderText, BsoFailColorBlend);
801
802 msgType = m_errorMonitor->GetState(&msgString);
803 ASSERT_EQ(msgType, VK_DBG_MSG_ERROR) << "Did not receive an error from Not Binding a ColorBlend State Object";
804 if (!strstr(msgString.c_str(),"Color-blend object not bound to this command buffer")) {
805 FAIL() << "Error received was not 'Color-blend object not bound to this command buffer'";
806 }
807}
808
809TEST_F(VkLayerTest, DepthStencilStateNotBound)
810{
811 VK_DBG_MSG_TYPE msgType;
812 std::string msgString;
813
814 TEST_DESCRIPTION("Simple Draw Call that validates failure when a depth-stencil state object is not bound beforehand");
815
816 VKTriangleTest(bindStateVertShaderText, bindStateFragShaderText, BsoFailDepthStencil);
817
818 msgType = m_errorMonitor->GetState(&msgString);
819 ASSERT_EQ(msgType, VK_DBG_MSG_ERROR) << "Did not receive an error from Not Binding a DepthStencil State Object";
820 if (!strstr(msgString.c_str(),"Depth-stencil object not bound to this command buffer")) {
821 FAIL() << "Error received was not 'Depth-stencil object not bound to this command buffer'";
822 }
Tony Barbourdb686622015-05-06 09:35:56 -0600823}
824
Mike Stroyan09aae812015-05-12 16:00:45 -0600825#if GTEST_IS_THREADSAFE
826struct thread_data_struct {
827 VkCmdBuffer cmdBuffer;
828 VkEvent event;
829 bool bailout;
830};
831
832extern "C" void *AddToCommandBuffer(void *arg)
833{
834 struct thread_data_struct *data = (struct thread_data_struct *) arg;
835 std::string msgString;
836
837 for (int i = 0; i<10000; i++) {
838 vkCmdSetEvent(data->cmdBuffer, data->event, VK_PIPE_EVENT_COMMANDS_COMPLETE);
839 if (data->bailout) {
840 break;
841 }
842 }
843 return NULL;
844}
845
846TEST_F(VkLayerTest, ThreadCmdBufferCollision)
847{
848 VK_DBG_MSG_TYPE msgType;
849 std::string msgString;
850 pthread_t thread;
851 pthread_attr_t thread_attr;
852
853 ASSERT_NO_FATAL_FAILURE(InitState());
854 ASSERT_NO_FATAL_FAILURE(InitViewport());
855 ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
856
857 VkCommandBufferObj cmdBuffer(m_device);
858
859 m_errorMonitor->ClearState();
860 pthread_attr_init(&thread_attr);
861 BeginCommandBuffer(cmdBuffer);
862
863 VkEventCreateInfo event_info;
864 VkEvent event;
865 VkMemoryRequirements mem_req;
866 size_t data_size = sizeof(mem_req);
867 VkResult err;
868
869 memset(&event_info, 0, sizeof(event_info));
870 event_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO;
871
872 err = vkCreateEvent(device(), &event_info, &event);
873 ASSERT_VK_SUCCESS(err);
874
875 err = vkGetObjectInfo(device(), VK_OBJECT_TYPE_EVENT, event, VK_OBJECT_INFO_TYPE_MEMORY_REQUIREMENTS,
876 &data_size, &mem_req);
877 ASSERT_VK_SUCCESS(err);
878
879 VkMemoryAllocInfo mem_info;
880 VkDeviceMemory event_mem;
881
882 ASSERT_NE(0, mem_req.size) << "vkGetObjectInfo (Event): Failed - expect events to require memory";
883
884 memset(&mem_info, 0, sizeof(mem_info));
885 mem_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO;
886 mem_info.allocationSize = mem_req.size;
887 mem_info.memProps = VK_MEMORY_PROPERTY_SHAREABLE_BIT;
888 mem_info.memPriority = VK_MEMORY_PRIORITY_NORMAL;
889 err = vkAllocMemory(device(), &mem_info, &event_mem);
890 ASSERT_VK_SUCCESS(err);
891
892 err = vkBindObjectMemory(device(), VK_OBJECT_TYPE_EVENT, event, 0, event_mem, 0);
893 ASSERT_VK_SUCCESS(err);
894
895 err = vkResetEvent(device(), event);
896 ASSERT_VK_SUCCESS(err);
897
898 struct thread_data_struct data;
899 data.cmdBuffer = cmdBuffer.obj();
900 data.event = event;
901 data.bailout = false;
902 m_errorMonitor->SetBailout(&data.bailout);
903 // Add many entries to command buffer from another thread.
904 pthread_create(&thread, &thread_attr, AddToCommandBuffer, (void *)&data);
905 // Add many entries to command buffer from this thread at the same time.
906 AddToCommandBuffer(&data);
907 pthread_join(thread, NULL);
908 EndCommandBuffer(cmdBuffer);
909
910 msgType = m_errorMonitor->GetState(&msgString);
911 ASSERT_EQ(msgType, VK_DBG_MSG_ERROR) << "Did not receive an err from using one VkCommandBufferObj in two threads";
912 if (!strstr(msgString.c_str(),"THREADING ERROR")) {
Mark Lobodzinski5f25be42015-05-14 15:08:13 -0500913 FAIL() << "Error received was not 'THREADING ERROR'";
Mike Stroyan09aae812015-05-12 16:00:45 -0600914 }
915
916}
917#endif
918
Tony Barbour30486ea2015-04-07 13:44:53 -0600919int main(int argc, char **argv) {
920 int result;
921
922 ::testing::InitGoogleTest(&argc, argv);
Tony Barbour01999182015-04-09 12:58:51 -0600923 VkTestFramework::InitArgs(&argc, argv);
Tony Barbour30486ea2015-04-07 13:44:53 -0600924
925 ::testing::AddGlobalTestEnvironment(new TestEnvironment);
926
927 result = RUN_ALL_TESTS();
928
Tony Barbour01999182015-04-09 12:58:51 -0600929 VkTestFramework::Finish();
Tony Barbour30486ea2015-04-07 13:44:53 -0600930 return result;
931}