// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "gpu/ipc/common/gpu_command_buffer_traits.h"

#include <stddef.h>
#include <stdint.h>

#include "base/strings/stringprintf.h"
#include "gpu/command_buffer/common/command_buffer_id.h"
#include "gpu/command_buffer/common/mailbox_holder.h"
#include "gpu/command_buffer/common/sync_token.h"
#include "gpu/ipc/common/vulkan_ycbcr_info.h"
#include "ui/gfx/buffer_format_util.h"

// Generate param traits write methods.
#include "ipc/param_traits_write_macros.h"
namespace IPC {
#include "gpu/ipc/common/gpu_command_buffer_traits_multi.h"
}  // namespace IPC

// Generate param traits read methods.
#include "ipc/param_traits_read_macros.h"
namespace IPC {
#include "gpu/ipc/common/gpu_command_buffer_traits_multi.h"
}  // namespace IPC

// Generate param traits log methods.
#include "ipc/param_traits_log_macros.h"
namespace IPC {
#include "gpu/ipc/common/gpu_command_buffer_traits_multi.h"
}  // namespace IPC

namespace IPC {

void ParamTraits<gpu::SyncToken>::Write(base::Pickle* m, const param_type& p) {
  DCHECK(!p.HasData() || p.verified_flush());

  WriteParam(m, p.verified_flush());
  WriteParam(m, p.namespace_id());
  WriteParam(m, p.command_buffer_id());
  WriteParam(m, p.release_count());
}

bool ParamTraits<gpu::SyncToken>::Read(const base::Pickle* m,
                                       base::PickleIterator* iter,
                                       param_type* p) {
  bool verified_flush = false;
  gpu::CommandBufferNamespace namespace_id =
      gpu::CommandBufferNamespace::INVALID;
  gpu::CommandBufferId command_buffer_id;
  uint64_t release_count = 0;

  if (!ReadParam(m, iter, &verified_flush) ||
      !ReadParam(m, iter, &namespace_id) ||
      !ReadParam(m, iter, &command_buffer_id) ||
      !ReadParam(m, iter, &release_count)) {
    return false;
  }

  p->Set(namespace_id, command_buffer_id, release_count);
  if (p->HasData()) {
    if (!verified_flush)
      return false;
    p->SetVerifyFlush();
  }

  return true;
}

void ParamTraits<gpu::SyncToken>::Log(const param_type& p, std::string* l) {
  *l += base::StringPrintf(
      "[%" PRId8 ":%" PRIX64 "] %" PRIu64, p.namespace_id(),
      p.command_buffer_id().GetUnsafeValue(), p.release_count());
}

void ParamTraits<gpu::Mailbox>::Write(base::Pickle* m, const param_type& p) {
  m->WriteBytes(p.name, sizeof(p.name));
}

bool ParamTraits<gpu::Mailbox>::Read(const base::Pickle* m,
                                     base::PickleIterator* iter,
                                     param_type* p) {
  const char* bytes = nullptr;
  if (!iter->ReadBytes(&bytes, sizeof(p->name)))
    return false;
  DCHECK(bytes);
  memcpy(p->name, bytes, sizeof(p->name));
  return true;
}

void ParamTraits<gpu::Mailbox>::Log(const param_type& p, std::string* l) {
  for (size_t i = 0; i < sizeof(p.name); ++i)
    *l += base::StringPrintf("%02x", p.name[i]);
}

void ParamTraits<gpu::MailboxHolder>::Write(base::Pickle* m,
                                            const param_type& p) {
  WriteParam(m, p.mailbox);
  WriteParam(m, p.sync_token);
  WriteParam(m, p.texture_target);
}

bool ParamTraits<gpu::MailboxHolder>::Read(const base::Pickle* m,
                                           base::PickleIterator* iter,
                                           param_type* p) {
  if (!ReadParam(m, iter, &p->mailbox) || !ReadParam(m, iter, &p->sync_token) ||
      !ReadParam(m, iter, &p->texture_target))
    return false;
  return true;
}

void ParamTraits<gpu::MailboxHolder>::Log(const param_type& p, std::string* l) {
  LogParam(p.mailbox, l);
  LogParam(p.sync_token, l);
  *l += base::StringPrintf(":%04x@", p.texture_target);
}

void ParamTraits<gpu::VulkanYCbCrInfo>::Write(base::Pickle* m,
                                              const param_type& p) {
  WriteParam(m, p.image_format);
  WriteParam(m, p.external_format);
  WriteParam(m, p.suggested_ycbcr_model);
  WriteParam(m, p.suggested_ycbcr_range);
  WriteParam(m, p.suggested_xchroma_offset);
  WriteParam(m, p.suggested_ychroma_offset);
  WriteParam(m, p.format_features);
}

bool ParamTraits<gpu::VulkanYCbCrInfo>::Read(const base::Pickle* m,
                                             base::PickleIterator* iter,
                                             param_type* p) {
  if (!ReadParam(m, iter, &p->image_format) ||
      !ReadParam(m, iter, &p->external_format) ||
      !ReadParam(m, iter, &p->suggested_ycbcr_model) ||
      !ReadParam(m, iter, &p->suggested_ycbcr_range) ||
      !ReadParam(m, iter, &p->suggested_xchroma_offset) ||
      !ReadParam(m, iter, &p->suggested_ychroma_offset) ||
      !ReadParam(m, iter, &p->format_features)) {
    return false;
  }
  return true;
}

// Note that we are casting uint64_t explicitly to long long otherwise it gets
// implicit cast to long for 64 bit OS and long long for 32 bit OS.
void ParamTraits<gpu::VulkanYCbCrInfo>::Log(const param_type& p,
                                            std::string* l) {
  *l += base::StringPrintf(
      "[%u] , [%llu], [%u], [%u], [%u], [%u], [%u]", p.image_format,
      static_cast<long long>(p.external_format), p.suggested_ycbcr_model,
      p.suggested_ycbcr_range, p.suggested_xchroma_offset,
      p.suggested_ychroma_offset, p.format_features);
}

void ParamTraits<gpu::GpuMemoryBufferFormatSet>::Write(base::Pickle* m,
                                                       const param_type& p) {
  WriteParam(m, p.ToEnumBitmask());
}

bool ParamTraits<gpu::GpuMemoryBufferFormatSet>::Read(
    const base::Pickle* m,
    base::PickleIterator* iter,
    param_type* p) {
  uint64_t bitmask = 0;
  if (!ReadParam(m, iter, &bitmask)) {
    return false;
  }
  // Check deserialized bitmask contains only bits GpuMemoryBufferFormatSet
  // expects to be set based on largest enum it expects.
  if (bitmask & ~gpu::GpuMemoryBufferFormatSet::All().ToEnumBitmask()) {
    return false;
  }
  *p = gpu::GpuMemoryBufferFormatSet::FromEnumBitmask(bitmask);
  return true;
}

void ParamTraits<gpu::GpuMemoryBufferFormatSet>::Log(const param_type& p,
                                                     std::string* l) {
  std::string str;
  for (gfx::BufferFormat format : p) {
    if (!str.empty()) {
      str += "|";
    }
    str += gfx::BufferFormatToString(format);
  }
  *l += str;
}

}  // namespace IPC