layers: Validate maxComputeWorkGroupSize

Validate maxComputeWorkGroupSize in create compute pipelines.

Change-Id: Ie7e574d2e3263e197ad9cf11ddbf5174af3de370
diff --git a/layers/shader_validation.cpp b/layers/shader_validation.cpp
index 8d5830c..45f743f 100644
--- a/layers/shader_validation.cpp
+++ b/layers/shader_validation.cpp
@@ -2616,7 +2616,9 @@
             }
         }
     }
-
+    if (pStage->stage == VK_SHADER_STAGE_COMPUTE_BIT) {
+        skip |= ValidateComputeWorkGroupSizes(module);
+    }
     return skip;
 }
 
@@ -2913,3 +2915,59 @@
                  : new shader_module());
     shaderModuleMap[*pShaderModule] = std::move(new_shader_module);
 }
+
+bool CoreChecks::ValidateComputeWorkGroupSizes(const shader_module *shader) {
+    bool skip = false;
+    uint32_t local_size_x = 0;
+    uint32_t local_size_y = 0;
+    uint32_t local_size_z = 0;
+    if (FindLocalSize(shader, local_size_x, local_size_y, local_size_z)) {
+        if (local_size_x > phys_dev_props.limits.maxComputeWorkGroupSize[0]) {
+            skip |=
+                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
+                        HandleToUint64(shader->vk_shader_module), "UNASSIGNED-features-limits-maxComputeWorkGroupSize",
+                        "ShaderMdoule %s local_size_x (%" PRIu32 ") exceeds device limit maxComputeWorkGroupSize[0] (%" PRIu32 ").",
+                        report_data->FormatHandle(shader->vk_shader_module).c_str(), local_size_x,
+                        phys_dev_props.limits.maxComputeWorkGroupSize[0]);
+        }
+        if (local_size_y > phys_dev_props.limits.maxComputeWorkGroupSize[1]) {
+            skip |=
+                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
+                        HandleToUint64(shader->vk_shader_module), "UNASSIGNED-features-limits-maxComputeWorkGroupSize",
+                        "ShaderMdoule %s local_size_y (%" PRIu32 ") exceeds device limit maxComputeWorkGroupSize[1] (%" PRIu32 ").",
+                        report_data->FormatHandle(shader->vk_shader_module).c_str(), local_size_x,
+                        phys_dev_props.limits.maxComputeWorkGroupSize[1]);
+        }
+        if (local_size_z > phys_dev_props.limits.maxComputeWorkGroupSize[2]) {
+            skip |=
+                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
+                        HandleToUint64(shader->vk_shader_module), "UNASSIGNED-features-limits-maxComputeWorkGroupSize",
+                        "ShaderMdoule %s local_size_z (%" PRIu32 ") exceeds device limit maxComputeWorkGroupSize[2] (%" PRIu32 ").",
+                        report_data->FormatHandle(shader->vk_shader_module).c_str(), local_size_x,
+                        phys_dev_props.limits.maxComputeWorkGroupSize[2]);
+        }
+
+        uint32_t limit = phys_dev_props.limits.maxComputeWorkGroupInvocations;
+        uint64_t invocations = local_size_x * local_size_y;
+        // Prevent overflow.
+        bool fail = false;
+        if (invocations > UINT32_MAX || invocations > limit) {
+            fail = true;
+        }
+        if (!fail) {
+            invocations *= local_size_z;
+            if (invocations > UINT32_MAX || invocations > limit) {
+                fail = true;
+            }
+        }
+        if (fail) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
+                            HandleToUint64(shader->vk_shader_module), "UNASSIGNED-features-limits-maxComputeWorkGroupInvocations",
+                            "ShaderMdoule %s local_size (%" PRIu32 ", %" PRIu32 ", %" PRIu32
+                            ") exceeds device limit maxComputeWorkGroupInvocations (%" PRIu32 ").",
+                            report_data->FormatHandle(shader->vk_shader_module).c_str(), local_size_x, local_size_y, local_size_z,
+                            limit);
+        }
+    }
+    return skip;
+}