intel: implement image functions

Untested.  Bugs are expected.
diff --git a/icd/intel/CMakeLists.txt b/icd/intel/CMakeLists.txt
index 74dbb08..014bb9e 100644
--- a/icd/intel/CMakeLists.txt
+++ b/icd/intel/CMakeLists.txt
@@ -24,6 +24,7 @@
     fence.c
     format.c
     gpu.c
+    img.c
     mem.c
     obj.c
     query.c
diff --git a/icd/intel/dispatch_tables.c b/icd/intel/dispatch_tables.c
index 29d91fd..e30f9ab 100644
--- a/icd/intel/dispatch_tables.c
+++ b/icd/intel/dispatch_tables.c
@@ -27,6 +27,7 @@
 #include "event.h"
 #include "fence.h"
 #include "format.h"
+#include "img.h"
 #include "gpu.h"
 #include "mem.h"
 #include "obj.h"
@@ -140,24 +141,6 @@
     return XGL_ERROR_UNAVAILABLE;
 }
 
-static XGL_RESULT XGLAPI intelCreateImage(
-    XGL_DEVICE                                  device,
-    const XGL_IMAGE_CREATE_INFO*                pCreateInfo,
-    XGL_IMAGE*                                  pImage)
-{
-    return XGL_ERROR_UNAVAILABLE;
-}
-
-static XGL_RESULT XGLAPI intelGetImageSubresourceInfo(
-    XGL_IMAGE                                   image,
-    const XGL_IMAGE_SUBRESOURCE*                pSubresource,
-    XGL_SUBRESOURCE_INFO_TYPE                   infoType,
-    XGL_SIZE*                                   pDataSize,
-    XGL_VOID*                                   pData)
-{
-    return XGL_ERROR_UNAVAILABLE;
-}
-
 static XGL_RESULT XGLAPI intelCreateImageView(
     XGL_DEVICE                                  device,
     const XGL_IMAGE_VIEW_CREATE_INFO*           pCreateInfo,
diff --git a/icd/intel/img.c b/icd/intel/img.c
index cbf28e3..8d7e9c1 100644
--- a/icd/intel/img.c
+++ b/icd/intel/img.c
@@ -1018,3 +1018,193 @@
    layout->hiz_stride = u_align(hz_width, 128);
    layout->hiz_height = u_align(hz_height, 32);
 }
+
+static bool
+img_alloc_slices(struct intel_img *img,
+                 XGL_UINT levels, XGL_INT depth,
+                 XGL_UINT array_size)
+{
+   struct intel_img_slice *slices;
+   int total_depth, lv;
+
+   /* sum the depths of all levels */
+   total_depth = 0;
+   for (lv = 0; lv < levels; lv++)
+      total_depth += u_minify(depth, lv);
+
+   /*
+    * There are (depth * tex->base.array_size) slices in total.  Either depth
+    * is one (non-3D) or templ->array_size is one (non-array), but it does
+    * not matter.
+    */
+   slices = icd_alloc(sizeof(*slices) * total_depth * array_size,
+           0, XGL_SYSTEM_ALLOC_INTERNAL);
+   if (!slices)
+      return false;
+
+   img->slices[0] = slices;
+
+   /* point to the respective positions in the buffer */
+   for (lv = 1; lv < levels; lv++) {
+      img->slices[lv] = img->slices[lv - 1] +
+         u_minify(depth, lv - 1) * array_size;
+   }
+
+   return true;
+}
+
+static void img_destroy(struct intel_obj *obj)
+{
+    struct intel_img *img = intel_img_from_obj(obj);
+
+    intel_img_destroy(img);
+}
+
+static XGL_RESULT img_get_info(struct intel_base *base, int type,
+                               XGL_SIZE *size, XGL_VOID *data)
+{
+    struct intel_img *img = intel_img_from_base(base);
+    XGL_RESULT ret = XGL_SUCCESS;
+
+    switch (type) {
+    case XGL_INFO_TYPE_MEMORY_REQUIREMENTS:
+        {
+            XGL_MEMORY_REQUIREMENTS *mem_req = data;
+
+            mem_req->size = img->bo_stride * img->bo_height;
+            mem_req->alignment = 4096;
+            mem_req->heapCount = 1;
+            mem_req->heaps[0] = 0;
+
+            *size = sizeof(*mem_req);
+        }
+        break;
+    default:
+        ret = intel_base_get_info(base, type, size, data);
+        break;
+    }
+
+    return ret;
+}
+
+XGL_RESULT intel_img_create(struct intel_dev *dev,
+                            const XGL_IMAGE_CREATE_INFO *info,
+                            struct intel_img **img_ret)
+{
+    struct tex_layout layout;
+    struct intel_img *img;
+    XGL_RESULT ret;
+
+    img = (struct intel_img *) intel_base_create(sizeof(*img),
+            dev->base.dbg, XGL_DBG_OBJECT_IMAGE, info, 0);
+    if (!img)
+        return XGL_ERROR_OUT_OF_MEMORY;
+
+    if (!img_alloc_slices(img, info->mipLevels, info->extent.depth,
+                info->arraySize)) {
+        intel_img_destroy(img);
+        return XGL_ERROR_OUT_OF_MEMORY;
+    }
+
+    ret = tex_layout_init(&layout, dev->gpu, info, img->slices);
+    if (ret != XGL_SUCCESS) {
+        intel_img_destroy(img);
+        return ret;
+    }
+
+    if (info->imageType == XGL_IMAGE_3D)
+        tex_layout_3d(&layout);
+    else
+        tex_layout_2d(&layout);
+
+    if (!tex_layout_calculate_bo_size(&layout)) {
+        intel_img_destroy(img);
+        return XGL_ERROR_INVALID_MEMORY_SIZE;
+    }
+
+    tex_layout_calculate_hiz_size(&layout);
+
+    /* TODO */
+    if (layout.hiz || layout.separate_stencil) {
+        intel_dev_log(dev, XGL_DBG_MSG_ERROR, XGL_VALIDATION_LEVEL_0,
+                XGL_NULL_HANDLE, 0, 0, "HiZ or separate stencil enabled");
+        intel_img_destroy(img);
+        return XGL_ERROR_INVALID_MEMORY_SIZE;
+    }
+
+    img->bo_format = layout.format;
+    img->tiling = layout.tiling;
+    img->bo_stride = layout.bo_stride;
+    img->bo_height = layout.bo_height;
+    img->block_width = layout.block_width;
+    img->block_height = layout.block_height;
+    img->block_size = layout.block_size;
+    img->halign_8 = (layout.align_i == 8);
+    img->valign_4 = (layout.align_j == 4);
+    img->array_spacing_full = layout.array_spacing_full;
+    img->interleaved = layout.interleaved;
+
+    img->obj.destroy = img_destroy;
+    img->obj.base.get_info = img_get_info;
+
+    *img_ret = img;
+
+    return XGL_SUCCESS;
+}
+
+void intel_img_destroy(struct intel_img *img)
+{
+    if (img->slices[0])
+        icd_free(img->slices[0]);
+
+    intel_base_destroy(&img->obj.base);
+}
+
+XGL_RESULT XGLAPI intelCreateImage(
+    XGL_DEVICE                                  device,
+    const XGL_IMAGE_CREATE_INFO*                pCreateInfo,
+    XGL_IMAGE*                                  pImage)
+{
+    struct intel_dev *dev = intel_dev(device);
+
+    return intel_img_create(dev, pCreateInfo, (struct intel_img **) pImage);
+}
+
+XGL_RESULT XGLAPI intelGetImageSubresourceInfo(
+    XGL_IMAGE                                   image,
+    const XGL_IMAGE_SUBRESOURCE*                pSubresource,
+    XGL_SUBRESOURCE_INFO_TYPE                   infoType,
+    XGL_SIZE*                                   pDataSize,
+    XGL_VOID*                                   pData)
+{
+    const struct intel_img *img = intel_img(image);
+    XGL_RESULT ret = XGL_SUCCESS;
+
+    switch (infoType) {
+    case XGL_INFO_TYPE_SUBRESOURCE_LAYOUT:
+        {
+            XGL_SUBRESOURCE_LAYOUT *layout = (XGL_SUBRESOURCE_LAYOUT *) pData;
+            const struct intel_img_slice *slice =
+                &img->slices[pSubresource->mipLevel][pSubresource->arraySlice];
+            const unsigned int bx = slice->x / img->block_width;
+            const unsigned int by = slice->y / img->block_height;
+
+            *pDataSize = sizeof(XGL_SUBRESOURCE_LAYOUT);
+
+            /*
+             * size is not readily available and depthPitch might not be
+             * available.  Leave them alone for now.
+             */
+            layout->offset = by * img->bo_stride + bx * img->block_size;
+            layout->size = 0;
+            layout->rowPitch = img->bo_stride;
+            layout->depthPitch = 0;
+        }
+        break;
+    default:
+        ret = XGL_ERROR_INVALID_VALUE;
+        break;
+    }
+
+    return ret;
+}
diff --git a/icd/intel/img.h b/icd/intel/img.h
index 68c8c35..b2ba888 100644
--- a/icd/intel/img.h
+++ b/icd/intel/img.h
@@ -25,6 +25,7 @@
 #ifndef IMG_H
 #define IMG_H
 
+#include "kmd/winsys.h"
 #include "intel.h"
 #include "obj.h"
 
@@ -41,6 +42,58 @@
 
 struct intel_img {
     struct intel_obj obj;
+
+    XGL_FORMAT bo_format;
+
+    enum intel_tiling_mode tiling;
+    unsigned long bo_stride; /* distance between two block rows in bytes */
+    unsigned long bo_height;
+
+    unsigned block_width;
+    unsigned block_height;
+    unsigned block_size;
+
+    /* true if the mip level alignments are stricter */
+    bool halign_8, valign_4;
+    /* true if space is reserved between layers */
+    bool array_spacing_full;
+    /* true if samples are interleaved */
+    bool interleaved;
+
+    struct intel_img_slice *slices[INTEL_IMG_MAX_LEVELS];
 };
 
+static inline struct intel_img *intel_img(XGL_IMAGE image)
+{
+    return (struct intel_img *) image;
+}
+
+static inline struct intel_img *intel_img_from_base(struct intel_base *base)
+{
+    return (struct intel_img *) base;
+}
+
+static inline struct intel_img *intel_img_from_obj(struct intel_obj *obj)
+{
+    return intel_img_from_base(&obj->base);
+}
+
+XGL_RESULT intel_img_create(struct intel_dev *dev,
+                            const XGL_IMAGE_CREATE_INFO *info,
+                            struct intel_img **img_ret);
+
+void intel_img_destroy(struct intel_img *img);
+
+XGL_RESULT XGLAPI intelCreateImage(
+    XGL_DEVICE                                  device,
+    const XGL_IMAGE_CREATE_INFO*                pCreateInfo,
+    XGL_IMAGE*                                  pImage);
+
+XGL_RESULT XGLAPI intelGetImageSubresourceInfo(
+    XGL_IMAGE                                   image,
+    const XGL_IMAGE_SUBRESOURCE*                pSubresource,
+    XGL_SUBRESOURCE_INFO_TYPE                   infoType,
+    XGL_SIZE*                                   pDataSize,
+    XGL_VOID*                                   pData);
+
 #endif /* IMG_H */
diff --git a/icd/intel/obj.c b/icd/intel/obj.c
index 7bbd054..041c091 100644
--- a/icd/intel/obj.c
+++ b/icd/intel/obj.c
@@ -96,6 +96,10 @@
         assert(dbg->type == XGL_DBG_OBJECT_QUERY_POOL);
         shallow_copy = sizeof(XGL_QUERY_POOL_CREATE_INFO);
         break;
+    case XGL_STRUCTURE_TYPE_IMAGE_CREATE_INFO:
+        assert(dbg->type == XGL_DBG_OBJECT_IMAGE);
+        shallow_copy = sizeof(XGL_IMAGE_CREATE_INFO);
+        break;
     default:
         return false;
         break;